취미중독

하고 싶은 일이 너무 많아

학습자료/Next.js 초보자 학습 과정

# Next.js 가이드 / 챕터 9: Components - 레고 블록처럼 조립하기

depilled 2025. 8. 11. 18:09

# 챕터 9: Components - 레고 블록처럼 조립하기

## 서론

지금까지 우리는 HTML 구조를 만들고 CSS로 스타일을 입히는 방법을 배웠습니다. 하지만 실제 웹 개발에서는 같은 코드를 반복해서 작성하는 경우가 많습니다. 예를 들어, 웹사이트에 10개의 카드를 만든다면 같은 HTML 구조를 10번 복사해야 할까요? 이런 비효율적인 작업을 해결하기 위해 등장한 것이 바로 컴포넌트(Component)입니다.

컴포넌트는 레고 블록과 같습니다. 한 번 만들어두면 필요할 때마다 가져다 쓸 수 있고, 여러 개를 조합하여 복잡한 구조물도 만들 수 있습니다. React와 Next.js의 핵심은 바로 이 컴포넌트 기반 개발입니다. 이번 챕터에서는 컴포넌트의 개념을 이해하고, 실제로 재사용 가능한 컴포넌트를 만드는 방법을 배워보겠습니다.

## 본론

### 컴포넌트란 무엇인가

컴포넌트는 독립적이고 재사용 가능한 코드 조각입니다. UI의 한 부분을 캡슐화하여 마치 하나의 태그처럼 사용할 수 있게 만듭니다. 예를 들어, 버튼, 카드, 내비게이션 바 등을 각각 하나의 컴포넌트로 만들 수 있습니다.

React에서 컴포넌트를 만드는 것은 JavaScript 함수를 만드는 것과 같습니다. 함수가 입력을 받아 출력을 반환하듯이, 컴포넌트는 속성(props)을 받아 JSX를 반환합니다. 이렇게 함수 형태로 만든 컴포넌트를 함수형 컴포넌트라고 부릅니다.

### 첫 번째 컴포넌트 만들기

components 폴더를 만들고 그 안에 첫 번째 컴포넌트를 만들어봅시다. app 폴더와 같은 레벨에 components 폴더를 생성합니다(my-first-website(root)/components):


// components/WelcomeMessage.jsx
export default function WelcomeMessage() {
  return (
    <div className="bg-blue-100 border-2 border-blue-300 rounded-lg p-6 m-4">
      <h2 className="text-2xl font-bold text-blue-800 mb-2">
        환영합니다! 👋
      </h2>
      <p className="text-blue-600">
        이것은 재사용 가능한 컴포넌트입니다.
        어디서든 사용할 수 있습니다.
      </p>
    </div>
  )
}




이제 이 컴포넌트를 페이지에서 사용해봅시다:

```jsx

// app/page.js
import WelcomeMessage from '../components/WelcomeMessage'

export default function Home() {
  return (
    <div className="p-8">
      <h1 className="text-3xl font-bold mb-6">
        컴포넌트 사용 예제
      </h1>
      
      {/* 컴포넌트를 여러 번 사용할 수 있습니다 */}
      <WelcomeMessage />
      <WelcomeMessage />
      <WelcomeMessage />
    </div>
  )
}



보셨나요? WelcomeMessage 컴포넌트를 한 번 만들고 세 번 사용했습니다. 이것이 컴포넌트의 힘입니다!

### 컴포넌트 구조화하기

컴포넌트는 다른 컴포넌트를 포함할 수 있습니다. 이를 컴포지션(Composition)이라고 합니다. 작은 컴포넌트들을 조합하여 큰 컴포넌트를 만드는 것입니다:

// components/Button.jsx
export default function Button() {
  return (
    <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition-colors">
      클릭하세요
    </button>
  )
}

// components/Card.jsx
import Button from './Button'

export default function Card() {
  return (
    <div className="max-w-sm rounded overflow-hidden shadow-lg bg-white">
      <div className="h-48 bg-gradient-to-r from-blue-400 to-purple-500"></div>
      <div className="px-6 py-4">
        <h3 className="font-bold text-xl mb-2">카드 제목</h3>
        <p className="text-gray-700 text-base mb-4">
          카드 안에 버튼 컴포넌트를 포함시킬 수 있습니다.
        </p>
        <Button />
      </div>
    </div>
  )
}

// components/CardList.jsx  
import Card from './Card'

export default function CardList() {
  return (
    <div className="grid grid-cols-1 md:grid-cols-3 gap-6 p-6">
      <Card />
      <Card />
      <Card />
    </div>
  )
}



### 컴포넌트 파일 구조 관리하기

프로젝트가 커질수록 컴포넌트를 체계적으로 관리하는 것이 중요합니다. 일반적으로 사용되는 폴더 구조를 소개합니다:

components/
  ├── common/           # 공통으로 사용되는 컴포넌트
  │   ├── Button.jsx
  │   ├── Input.jsx
  │   └── Modal.jsx
  ├── layout/          # 레이아웃 관련 컴포넌트
  │   ├── Header.jsx
  │   ├── Footer.jsx
  │   └── Sidebar.jsx
  └── features/        # 특정 기능별 컴포넌트
      ├── ProductCard.jsx
      ├── UserProfile.jsx
      └── SearchBar.jsx



### 컴포넌트 명명 규칙

컴포넌트를 만들 때 지켜야 할 중요한 규칙들이 있습니다:

1. **컴포넌트 이름은 항상 대문자로 시작합니다** (PascalCase)
2. **파일명도 컴포넌트 이름과 동일하게 만듭니다**
3. **하나의 파일에는 하나의 컴포넌트만 export default로 내보냅니다**
4. **의미 있는 이름을 사용합니다**

// ✅ 좋은 예시
export default function ProductCard() { ... }
export default function NavigationBar() { ... }
export default function UserProfileWidget() { ... }

// ❌ 나쁜 예시
export default function productcard() { ... }  // 소문자 시작
export default function PC() { ... }           // 너무 짧고 불명확
export default function Component1() { ... }   // 의미 없는 이름



### 실습: 재사용 가능한 알림 컴포넌트 만들기

실제로 유용한 알림(Alert) 컴포넌트를 만들어봅시다:

// components/Alert.jsx
export default function Alert() {
  return (
    <div className="border-l-4 p-4 mb-4">
      {/* 정보 알림 */}
      <div className="border-blue-500 bg-blue-50 mb-4">
        <div className="flex items-center">
          <div className="text-blue-500 mr-3">ℹ️</div>
          <div>
            <p className="text-blue-800 font-semibold">정보</p>
            <p className="text-blue-600">유용한 정보를 제공합니다.</p>
          </div>
        </div>
      </div>
      
      {/* 성공 알림 */}
      <div className="border-green-500 bg-green-50 mb-4">
        <div className="flex items-center">
          <div className="text-green-500 mr-3">✅</div>
          <div>
            <p className="text-green-800 font-semibold">성공</p>
            <p className="text-green-600">작업이 성공적으로 완료되었습니다.</p>
          </div>
        </div>
      </div>
      
      {/* 경고 알림 */}
      <div className="border-yellow-500 bg-yellow-50 mb-4">
        <div className="flex items-center">
          <div className="text-yellow-500 mr-3">⚠️</div>
          <div>
            <p className="text-yellow-800 font-semibold">경고</p>
            <p className="text-yellow-600">주의가 필요한 상황입니다.</p>
          </div>
        </div>
      </div>
      
      {/* 에러 알림 */}
      <div className="border-red-500 bg-red-50">
        <div className="flex items-center">
          <div className="text-red-500 mr-3">❌</div>
          <div>
            <p className="text-red-800 font-semibold">에러</p>
            <p className="text-red-600">문제가 발생했습니다.</p>
          </div>
        </div>
      </div>
    </div>
  )
}



### 컴포넌트의 장점

컴포넌트를 사용하면 다음과 같은 이점이 있습니다:

**1. 재사용성**: 한 번 만든 컴포넌트를 여러 곳에서 사용할 수 있습니다.

export default function HomePage() {
  return (
    <div>
      <Button />  {/* 홈페이지에서 사용 */}
    </div>
  )
}

export default function AboutPage() {
  return (
    <div>
      <Button />  {/* 소개 페이지에서도 같은 버튼 사용 */}
    </div>
  )
}



**2. 유지보수성**: 컴포넌트 하나만 수정하면 사용된 모든 곳에 반영됩니다.

// Button.jsx를 수정하면
export default function Button() {
  return (
    <button className="bg-green-500 ...">  {/* blue를 green으로 변경 */}
      클릭하세요
    </button>
  )
}
// 모든 페이지의 버튼 색상이 자동으로 변경됩니다!



**3. 가독성**: 코드가 더 읽기 쉬워집니다.

// 컴포넌트 사용 전 - 복잡한 HTML 구조
<div className="max-w-sm rounded overflow-hidden shadow-lg">
  <div className="h-48 bg-gradient-to-r from-blue-400 to-purple-500"></div>
  <div className="px-6 py-4">
    <h3 className="font-bold text-xl mb-2">...</h3>
    <p className="text-gray-700 text-base">...</p>
  </div>
</div>

// 컴포넌트 사용 후 - 간단하고 명확
<ProductCard />



### 실습: 완전한 컴포넌트 기반 페이지 만들기

지금까지 배운 내용을 종합하여 여러 컴포넌트로 구성된 페이지를 만들어봅시다:

// app/page.js
import WelcomeMessage from '../components/WelcomeMessage'
import CardList from '../components/CardList'
import Alert from '../components/Alert'

export default function Home() {
  return (
    <div className="min-h-screen bg-gray-50">
      {/* 페이지 헤더 */}
      <div className="bg-white shadow-sm">
        <div className="max-w-6xl mx-auto px-4 py-8">
          <h1 className="text-4xl font-bold text-gray-800 text-center mb-2">
            컴포넌트 갤러리
          </h1>
          <p className="text-gray-600 text-center">
            재사용 가능한 컴포넌트들로 구성된 웹사이트입니다
          </p>
        </div>
      </div>

      {/* 환영 메시지 컴포넌트 */}
      <div className="max-w-6xl mx-auto px-4 py-8">
        <WelcomeMessage />
      </div>

      {/* 알림 컴포넌트 */}
      <div className="max-w-6xl mx-auto px-4">
        <Alert />
      </div>

      {/* 카드 리스트 컴포넌트 */}
      <div className="max-w-6xl mx-auto px-4 py-8">
        <h2 className="text-2xl font-bold mb-6 text-gray-800">
          추천 콘텐츠
        </h2>
        <CardList />
      </div>

      {/* 추가 섹션 */}
      <div className="max-w-6xl mx-auto px-4 py-8">
        <div className="bg-white rounded-lg shadow-md p-6">
          <h3 className="text-xl font-bold mb-4">컴포넌트의 장점</h3>
          <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
            <div className="text-center p-4 bg-blue-50 rounded-lg">
              <div className="text-3xl mb-2">🔄</div>
              <h4 className="font-semibold mb-2">재사용성</h4>
              <p className="text-sm text-gray-600">
                한 번 만든 컴포넌트를 여러 곳에서 사용할 수 있습니다
              </p>
            </div>
            <div className="text-center p-4 bg-green-50 rounded-lg">
              <div className="text-3xl mb-2">🛠️</div>
              <h4 className="font-semibold mb-2">유지보수</h4>
              <p className="text-sm text-gray-600">
                컴포넌트 하나만 수정하면 모든 곳에 반영됩니다
              </p>
            </div>
            <div className="text-center p-4 bg-purple-50 rounded-lg">
              <div className="text-3xl mb-2">📖</div>
              <h4 className="font-semibold mb-2">가독성</h4>
              <p className="text-sm text-gray-600">
                코드가 더 읽기 쉽고 이해하기 쉬워집니다
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>
  )
}



## 결론

컴포넌트는 현대 웹 개발의 핵심입니다. 레고 블록처럼 작은 조각들을 만들고 조립하여 복잡한 웹사이트를 효율적으로 구축할 수 있습니다. 이번 챕터에서 우리는 컴포넌트의 개념, 생성 방법, 구조화, 명명 규칙, 그리고 실제 활용 방법까지 배웠습니다.

컴포넌트를 사용하면 코드의 재사용성이 높아지고, 유지보수가 쉬워지며, 팀 협업도 원활해집니다. 한 번 잘 만들어둔 컴포넌트는 프로젝트 전체에서 계속 활용할 수 있는 자산이 됩니다.

다음 챕터에서는 컴포넌트를 더욱 유연하게 만들어주는 Props에 대해 배워보겠습니다. 눈치채신 분들도 계시겠지만 Alert component를 상황에 맞게 나오게 해야 하는 것이 맞지 않을까 싶으실 겁니다. 앞으로 배우실 Props를 사용하면 같은 컴포넌트라도 다른 내용과 스타일을 표시할 수 있어, 상황에 맞는 진정한 재사용성을 실현할 수 있습니다!