React Todo 앱 - 컴포넌트 분리하기
앞서 설계한 Todo 앱을 실제로 파일 단위로 쪼개서 구현한다. export/import로 컴포넌트를 분리하는 방법부터 TodoItem, TodoList를 만들고 App에서 연결하는 과정, 기본 레이아웃까지 다룬다.
컴포넌트를 파일로 분리하기 - import와 export
지금까지는 한 파일 안에 여러 컴포넌트를 함께 작성했다. 이제부터는 컴포넌트마다 별도의 파일로 나누고, export/import로 서로 연결한다.
// src/Greeting.jsx
function Greeting() {
return <h2>안녕하세요!</h2>;
}
export default Greeting;
// src/App.jsx
import Greeting from "./Greeting";
function App() {
return <Greeting />;
}
export default App;
Greeting.jsx에서 export default Greeting은 "이 컴포넌트를 다른 파일에서 가져다 쓸 수 있게 내보낸다"는 뜻이고, App.jsx에서 import Greeting from "./Greeting"은 "같은 폴더에 있는 Greeting.jsx 파일에서 내보낸 걸 가져온다"는 뜻이다.
import 경로에는 왜 ./를 붙이고, 확장자는 왜 안 써도 될까? ./는 "지금 이 파일과 같은 폴더에서 찾는다"는 뜻이다. ./가 없으면 React는 내가 만든 파일이 아니라 node_modules에 설치된 라이브러리를 찾으려고 한다. 확장자는 Vite가 자동으로 붙여서 찾아주기 때문에 생략해도 된다.
TodoItem.jsx 만들기
목록 안의 할 일 하나를 보여주는 컴포넌트다. 완료 여부에 따라 취소선만 표시해본다.
// src/TodoItem.jsx
function TodoItem({ todo }) {
return (
<li style={{ textDecoration: todo.completed ? "line-through" : "none" }}>
{todo.text}
</li>
);
}
export default TodoItem;
todo라는 객체 하나를 props로 통째로 받아서, todo.text, todo.completed처럼 필요한 값을 꺼내 쓰고 있다.
TodoList.jsx 만들기
todos 배열 전체를 받아서, map()으로 TodoItem을 여러 개 렌더링하는 컴포넌트다.
// src/TodoList.jsx
import TodoItem from "./TodoItem";
function TodoList({ todos }) {
return (
<ul>
{todos.map((todo) => (
<TodoItem key={todo.id} todo={todo} />
))}
</ul>
);
}
export default TodoList;
App.jsx에서 전체 연결하기
// src/App.jsx
import { useState } from "react";
import TodoList from "./TodoList";
function App() {
const [todos, setTodos] = useState([
{ id: 1, text: "React 공부하기", completed: false },
{ id: 2, text: "장보기", completed: true },
{ id: 3, text: "운동하기", completed: false },
]);
return (
<div>
<h1>Todo 리스트</h1>
<TodoList todos={todos} />
</div>
);
}
export default App;
App이 가지고 있는 todos state를 TodoList에게 props로 내려주고, TodoList는 그걸 다시 TodoItem에게 하나씩 내려준다. 앞서 배운 "부모→자식 데이터 전달"이 파일이 나뉜 상태에서도 똑같이 적용된다.
기본 레이아웃과 스타일 적용하기
<div style={{ maxWidth: "400px", margin: "0 auto", padding: "24px" }}>
<h1>Todo 리스트</h1>
<TodoList todos={todos} />
</div>
maxWidth와 margin: "0 auto"로 화면 가운데에 적당한 너비로 정렬해서, 이후 입력창과 버튼을 추가했을 때도 보기 좋은 레이아웃을 미리 잡아둔다.
실습 정리
실습 1) TodoItem.jsx 파일 만들기 — todo props를 받아서 텍스트를 <li>로 보여주는 컴포넌트를 작성하고 export default로 내보낸다.
실습 2) TodoList.jsx 파일 만들기 — TodoItem을 import해서 todos props를 map()으로 순회하며 렌더링한다.
실습 3) App.jsx에서 연결해서 화면에 렌더링하기 — App.jsx에서 TodoList를 import하고 todos state를 props로 전달해서 화면에 할 일 3개가 나타나는지 확인한다.
실습 4) 기본 스타일 적용하기 — App의 최상위 <div>에 style을 추가해서 적당한 너비로 가운데 정렬되도록 꾸며본다.
마무리
export default 컴포넌트명으로 내보내고import 컴포넌트명 from "./경로"로 가져오는 패턴이 파일 분리의 기본이다.App → TodoList → TodoItem처럼 props가 여러 단계를 거쳐 내려가도, 부모→자식 전달 방식 자체는 하나의 파일에서 쓰던 것과 동일하다.- 컴포넌트를 파일로 나누면 각 파일이 하나의 역할만 담당하게 되어, 나중에 기능을 수정하거나 찾을 때 훨씬 편해진다.
'FullStack FrontEnd' 카테고리의 다른 글
| React Todo 앱 - 삭제 기능 구현 (props drilling, filter) (0) | 2026.09.18 |
|---|---|
| React Todo 앱 - 추가 기능 구현 (콜백 패턴, 불변성) (0) | 2026.09.18 |
| React Todo 앱 설계하기 - 컴포넌트 트리와 상태 위치 결정 (0) | 2026.09.17 |
| React 폼 다루기 - Controlled Component 정리 (0) | 2026.09.17 |
| React useEffect 기초 정리 - 컴포넌트 생명주기, 의존성 배열 (0) | 2026.09.17 |