리액트 컴포넌트의 다양한 구성 방법
컴포넌트 구성만 잘해도 리액트의 절반은 마스터한 거예요.
구조화된 코드로 유지보수성과 재사용성을 동시에 잡아보세요!
안녕하세요, 여러분! 😊
오늘은 리액트에서 가장 핵심이 되는 개념 중 하나인 "컴포넌트 구성 방식"에 대해 함께 알아보려 해요.
단순히 UI를 나누는 것을 넘어서, 유지보수성과 확장성을 고려한 설계 방식까지 꼼꼼히 다룰 예정입니다.
실무에서도 바로 적용할 수 있는 팁과 예제들을 준비했으니 끝까지 함께 해주세요 😊
목차
1. 함수형 컴포넌트 기본 사용법 🧱
리액트를 처음 접하면 가장 먼저 마주하는 것이 바로 컴포넌트입니다.
특히 함수형 컴포넌트는 코드가 간결하고, React Hooks
와 함께 사용하면 훨씬 강력한 기능을 구현할 수 있어요.
이 파트에서는 함수형 컴포넌트를 어떻게 정의하고 사용하는지, 그리고 어떤 구조로 작성하는 것이 좋은지를 알아봅니다.
함수형 컴포넌트란 무엇인가요?
함수형 컴포넌트는 단순히 JavaScript 함수로 정의된 컴포넌트입니다.
과거에는 클래스형 컴포넌트를 더 많이 사용했지만, 현재는 함수형 컴포넌트와 훅(Hooks)이 중심입니다.
가장 기본적인 함수형 컴포넌트 예시는 아래와 같습니다:
function Hello() {
return <h1>안녕하세요!</h1>;
}
그리고 이것을 JSX 안에서 `<Hello />
` 와 같이 호출하면 실제로 해당 컴포넌트가 렌더링됩니다.
Props로 데이터 전달하기
컴포넌트를 재사용 가능하게 만드는 핵심 요소가 바로 props
입니다.
예를 들어 아래처럼 name을 전달해볼 수 있어요:
function Hello(props) {
return <h1>안녕하세요, {props.name}!</h1>;
}
호출 시에는 이렇게 사용합니다: <Hello name="민수" />
정리 🧩
- 함수형 컴포넌트는 간결하고 가독성이 좋다.
-
props
를 이용해 유연한 데이터 전달이 가능하다. - 리액트 훅(Hooks)과 함께 쓰면 상태관리도 간단하게 가능하다.
이제 컴포넌트의 뼈대를 이해하셨다면, 다음으로 JSX 구조와 여러 컴포넌트 간의 관계를 좀 더 깊게 들여다보겠습니다.
2. JSX 구조와 다중 컴포넌트 구성 🏗️
JSX는 자바스크립트 안에서 HTML을 작성하는 것처럼 보이게 해주는 리액트의 문법입니다.
실제로는 자바스크립트의 문법적 확장(Syntax Extension)이며, React.createElement로 변환됩니다.
그런데 여러분, JSX 안에 컴포넌트를 여러 개 중첩해서 작성할 수 있다는 점 알고 계셨나요?
JSX로 컴포넌트 중첩하기
JSX에서는 div
나 section
과 같은 태그로 여러 요소를 감싸거나, React.Fragment를 사용해 불필요한 DOM 생성 없이 컴포넌트를 중첩할 수 있어요.
function App() {
return (
<div>
<Header />
<MainContent />
<Footer />
</div>
);
}
이런 식으로 여러 컴포넌트를 한 곳에 모아 하나의 UI를 구성할 수 있습니다.
그리고 각각의 컴포넌트는 다시 자신만의 자식 컴포넌트를 가질 수 있어요.
Fragment를 활용한 DOM 최소화
JSX는 반드시 하나의 부모 요소로 감싸야 하는 특징이 있습니다.
그런데 불필요한 div
를 추가하고 싶지 않을 땐 어떻게 하냐구요?
바로 <React.Fragment>
또는 <> </>
문법을 사용할 수 있어요:
function Wrapper() {
return (
<>
<h2>제목입니다</h2>
<p>본문 내용입니다</p>
</>
);
}
불필요한 DOM 태그를 줄이면서도 JSX 규칙은 지킬 수 있어, 요즘은 정말 자주 쓰이는 방식입니다.
한눈에 정리 🧾
기법 | 설명 |
---|---|
중첩 컴포넌트 | 상위 컴포넌트에서 여러 하위 컴포넌트를 조합하여 UI 구성 |
Fragment 사용 | 불필요한 DOM 없이 여러 요소를 하나의 컴포넌트에서 반환 |
이제 컴포넌트를 여러 개로 나눠서 어떻게 재구성할 수 있는지 감이 오시죠?
다음은 실제로 이 컴포넌트들이 어떻게 조합되는지, 그 구조를 더 깊이 있게 다뤄볼게요.
3. 컴포넌트의 조합과 부모-자식 구조 🧩
리액트에서 진짜 재미있는 부분은 바로 컴포넌트 조합이에요.
단순히 UI를 나눈 것뿐만 아니라, 데이터를 상위에서 하위로 어떻게 흐르게 할지도 설계의 핵심입니다.
부모 → 자식 데이터 전달: Props 흐름
컴포넌트 간 조합은 데이터를 props로 넘기면서 구성됩니다.
예를 들어 App 컴포넌트에서 Profile 컴포넌트에 데이터를 전달해볼게요.
// 부모 컴포넌트
function App() {
return <Profile name="유나" age={28} />;
}
// 자식 컴포넌트
function Profile(props) {
return (
<div>
<p>이름: {props.name}</p>
<p>나이: {props.age}</p>
</div>
);
}
이처럼 컴포넌트는 마치 블록처럼 쌓아올릴 수 있고, 필요한 정보를 위에서 아래로 흘려보낼 수 있습니다.
자식 컴포넌트 안에 또 자식? 계층 구조 만들기
리액트에서는 컴포넌트를 계층적으로 구성할 수 있어요.
예를 들어, App 안에 Header가 있고, Header 안에 Logo와 Menu가 있는 구조처럼요.
function Header() {
return (
<header>
<Logo />
<Menu />
</header>
);
}
이런 방식으로 코드를 구조화하면 협업이나 유지보수 시 훨씬 수월합니다.
👀 요약하자면...
- 리액트 컴포넌트는 블록처럼 쌓고 조합하는 것이 가능하다.
- 상위 컴포넌트는 하위 컴포넌트에게 props를 통해 정보를 전달한다.
- 컴포넌트 계층을 명확히 구분하면 유지보수가 쉬워진다.
이제 컴포넌트가 서로 어떻게 연결되는지 감이 오셨죠?
다음 섹션에서는 개발자들이 즐겨 사용하는 패턴 중 하나인 '컨테이너-프리젠테이셔널 패턴'을 다뤄볼게요!
4. 컨테이너-프리젠테이셔널 패턴 🎭
컴포넌트를 구성할 때 가장 많이 사용되는 구조 중 하나가 바로 컨테이너(Container)와 프리젠테이셔널(Presentational) 패턴이에요.
이 방식은 로직과 UI를 명확히 분리할 수 있어서 협업과 유지보수에 탁월하답니다.
이 패턴이 왜 중요한가요?
리액트 앱이 커질수록 각 컴포넌트에 데이터 로직과 UI가 섞이기 쉬워요.
이러면 코드가 복잡해지고 재사용도 어려워지죠.
그래서 등장한 게 바로 이 패턴입니다.
쉽게 말해, '로직은 컨테이너가 처리하고, 화면은 프리젠테이셔널이 담당한다'는 거예요.
예제로 알아보는 분리 방법
// 프리젠테이셔널 컴포넌트
function UserProfile({ name, age }) {
return (
<div>
<h2>{name}</h2>
<p>{age}살</p>
</div>
);
}
// 컨테이너 컴포넌트
function UserProfileContainer() {
const user = { name: "혜진", age: 25 };
return <UserProfile name={user.name} age={user.age} />;
}
이런 방식으로 UI 로직은 단순하게
, 데이터는 별도로 관리
하면 확장성과 유지보수성이 극대화됩니다.
컨테이너 & 프리젠테이셔널 비교표 🔍
구분 | 컨테이너 | 프리젠테이셔널 |
---|---|---|
역할 | 데이터 처리, 상태 관리 | UI 렌더링 전담 |
관심사 | 비즈니스 로직 | 디자인 및 화면 구조 |
이제 프로젝트가 커져도, 로직은 로직대로, UI는 UI대로 명확하게 관리할 수 있겠죠?
다음은 프로젝트 구조를 깔끔하게 유지하는 폴더 구조 팁을 소개할게요!
5. 폴더 구조로 관리하는 방법 🗂️
리액트 프로젝트가 점점 커지면 한눈에 보기 어려운 '컴포넌트 지옥'에 빠질 수 있어요.
그래서 오늘은 폴더 구조를 체계적으로 구성해서 관리하는 법을 소개할게요!
기본적인 디렉터리 구조 예시
src/
│
├── components/ // 재사용 가능한 컴포넌트
│ └── Button.js
│
├── containers/ // 로직이 포함된 컴포넌트
│ └── UserContainer.js
│
├── pages/ // 페이지 단위 컴포넌트
│ └── Home.js
│
├── hooks/ // 커스텀 훅 저장소
│ └── useFetch.js
│
├── styles/ // 전역 또는 모듈 스타일
│ └── App.module.css
│
└── App.js // 루트 컴포넌트
이렇게 구성하면 각 책임에 따라 폴더가 분리되므로 찾기도 쉽고 관리도 훨씬 깔끔해집니다.
상황별 폴더 분리 전략
- 페이지 기반 프로젝트:
pages
중심 구조 추천 - 기능 기반 프로젝트:
features
폴더 아래에 관련 모듈 묶기 - 컴포넌트 수가 많을 경우: 공통 UI와 비즈니스 UI 구분
💡 팁 하나!
컴포넌트 파일이 많아지면 index.js
를 활용해 모듈을 한 번에 export하는 방식도 매우 유용합니다.
이렇게 하면 import Button from '../components/Button'
대신
import { Button } from '../components'
처럼 깔끔하게 사용할 수 있어요!
이제 폴더 구조까지 정리됐으니, 마지막으로 실무에서 바로 쓸 수 있는 컴포넌트 구성 팁들을 공유드릴게요 😉
6. 실무에서 유용한 컴포넌트 구성 팁 💡
이제 기본 개념과 구조는 충분히 익혔다면, 실무에서 바로 써먹을 수 있는 꿀팁들을 알아볼 시간이에요.
초보 개발자일수록 놓치기 쉬운 실수들을 방지하고, 더 효율적으로 개발하는 방법들을 알려드릴게요!
재사용 가능한 컴포넌트 만들기
비슷한 UI를 복붙하는 대신 props를 활용해 재사용 가능한 컴포넌트를 만들어보세요.
예를 들어 Button 컴포넌트 하나로 모든 버튼을 처리할 수 있습니다.
function Button({ label, onClick, type = "button" }) {
return (
<button type={type} onClick={onClick}>
{label}
</button>
);
}
파일명과 컴포넌트명은 반드시 일치
이건 React의 암묵적 약속 같은 거예요.
컴포넌트 이름이 `ProfileCard`라면 파일명은 `ProfileCard.js`로 짓는 것이 좋아요. 찾기 쉽고, 협업 시에도 혼동을 줄일 수 있습니다.
상태관리는 필요한 컴포넌트에만
useState
나 useEffect
는 필요한 곳에만 쓰세요.
모든 컴포넌트에 상태를 두면 관리 지옥이 시작돼요.
최대한 상위 컴포넌트에서 처리하고, props로 전달하세요.
🚀 실무 팁 요약
- 컴포넌트 이름과 파일명은 반드시 일치시킬 것
- props를 통해 유연한 재사용 구조 만들기
- 상태 관리는 꼭 필요한 경우에만, 상위에서 처리
이제 여러분도 실전에서 통하는 컴포넌트 설계를 할 수 있을 거예요! 🎉
마무리하며 🧩
지금까지 리액트 컴포넌트를 어떻게 구성하고 활용할 수 있는지에 대해 단계별로 살펴봤어요.
처음에는 컴포넌트 하나 만드는 것도 버거웠을 수 있지만, 이제는 구조화된 컴포넌트 설계와 재사용 가능한 패턴까지 이해하게 되셨을 거예요.
컴포넌트는 단순한 코드 블록이 아니라, 사용자와 상호작용하는 인터페이스의 조각입니다.
꾸준히 연습하고, 여러 프로젝트에서 실전 경험을 쌓다 보면 자연스럽게 '좋은 컴포넌트'가 무엇인지 눈에 들어오게 될 거예요.
다음 글에서는 이 컴포넌트들을 활용한 상태관리 기법과 컴포넌트 간 데이터 흐름에 대해 이야기해보려고 해요. 기대해주세요!
'React' 카테고리의 다른 글
리액트 훅 완전정복! 초보자를 위한 주요 훅 사용법 가이드 (0) | 2025.04.23 |
---|---|
리액트 컴포넌트 설계 마스터: Atomic Design, 합성, 상속 완전정복 (0) | 2025.04.23 |
Tailwind CSS 최신버전 설치와 사용법 가이드 (Vite 프로젝트 기준) (1) | 2025.04.23 |
리액트 컴포넌트의 기본 개념 이해하기 (0) | 2025.04.06 |
styled-components로 리액트 스타일링하기 (2) | 2025.04.05 |