Syw.Frontend

✅ React 기초 강좌

5단계. 간단한 프로젝트 실습

5-3. TodoItem 컴포넌트 분리

🎯 학습 목표

  • 하나의 파일에 몰린 코드를 기능 단위로 나눈다.
  • props를 통해 상태 및 이벤트 함수를 자식 컴포넌트에 전달한다.
  • 구조화된 코드로 유지보수성과 재사용성을 높인다.

📦 분리 구조

src/
├── App.jsx
├── components/
│   └── TodoItem.jsx

📄 components/TodoItem.jsx

function TodoItem({ todo, onToggle, onDelete }) {
  return (
    <li style={{ marginBottom: '10px' }}>
      <input type="checkbox"
        checked={todo.isDone}
        onChange={() => onToggle(todo.id)}
      />
      <span style={{
          marginLeft: '10px',
          textDecoration: todo.isDone ? 'line-through' : 'none',
          color: todo.isDone ? '#999' : '#000',
        }}
      >
        {todo.content}
      </span>
      <button onClick={() => onDelete(todo.id)} style={{ marginLeft: '10px' }}>
        삭제
      </button>
    </li>
  );
}

export default TodoItem;

📄 App.jsx (변경된 부분만)

import { useState } from 'react';
import TodoItem from './components/TodoItem';

function App() {
  const [todos, setTodos] = useState([]);
  const [text, setText] = useState('');

  const handleAdd = () => {
    const trimmed = text.trim();
    if (trimmed === '') return;

    const newTodo = {
      id: Date.now(),
      content: trimmed,
      isDone: false,
    };
    setTodos([newTodo, ...todos]);
    setText('');
  };

  const handleDelete = (id) => {
    setTodos(todos.filter((todo) => todo.id !== id));
  };

  const handleToggle = (id) => {
    setTodos(
      todos.map((todo) =>
        todo.id === id ? { ...todo, isDone: !todo.isDone } : todo
      )
    );
  };

  const handleKeyDown = (e) => {
    if (e.key === 'Enter') handleAdd();
  };

  return (
    <div style={{ padding: '30px' }}>
      <h1>🧹 Todo 리스트</h1>

      <div style={{ marginBottom: '20px' }}>
        <input type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
          onKeyDown={handleKeyDown}
          placeholder="할 일을 입력하세요"
        />
        <button onClick={handleAdd}>추가</button>
      </div>

      <ul style={{ listStyle: 'none', padding: 0 }}>
        {todos.map((todo) => (
          <TodoItem key={todo.id}
            todo={todo}
            onToggle={handleToggle}
            onDelete={handleDelete}
          />
        ))}
      </ul>

      <p>총 {todos.length}개의 할 일이 있습니다.</p>
    </div>
  );
}

export default App;

✅ 핵심 정리

분리 전 분리 후
코드가 한 파일에 집중됨 각 기능별로 역할 분리
map 내부에 JSX 로직 과다 TodoItem으로 추출
유지보수 어려움 props로 명확하게 전달

GitHub - heroyooi/react-app at ch5_3

✍️ 과제

  • TodoItem 외에도 다음 단계에서 TodoForm (입력창 + 버튼)도 별도 컴포넌트로 분리해보세요.
  • 컴포넌트 역할에 따라 나눠진 구조가 왜 더 좋은지 스스로 정리해보세요.

💬 댓글

    ※ 로그인 후 댓글을 작성할 수 있습니다.