Todo 앱
Source: Dev.to
소개
첫 번째 로직‑중심 프로젝트(카운터)를 마친 뒤, 복잡성 측면에서 다음 자연스러운 단계로 나아가고 싶었습니다 — UI를 개선하는 것이 아니라 사고 방식을 도전하고 싶었습니다.
그 결과 프로젝트 2: Todo App (Logic‑First, Not UI) 를 시작하게 되었습니다.
왜 Todo App인가?
카운터는 단일 값 상태 로직을 이해하는 데 도움이 되었습니다. Todo 앱은 다음과 같은 사고를 요구합니다:
- 단일 값이 아닌 배열
- CRUD 작업(추가, 업데이트, 삭제)
- 조건부 렌더링
- 엣지 케이스와 상태 일관성
많은 React 학습자들이 여기서 어려움을 겪는데, 바로 이 지점이 성장하기에 완벽한 장소가 됩니다.
이 프로젝트의 목표는 화려한 인터페이스를 만드는 것이 아니라 문제 해결 접근 방식을 강화하고, 예측 가능한 상태 업데이트를 작성하며, 거의 모든 프론트엔드 애플리케이션에 나타나는 실제 로직 시나리오를 다루는 것이었습니다.
이 글에서는 Todo 앱을 단계별로 어떻게 접근했는지, 로직 선택, 겪은 실수, 그리고 그것을 해결하면서 배운 점을 상세히 설명하겠습니다.
단계별 개발 🚀
레벨 1: 검증이 포함된 Todo 생성 추가
커밋: Level 1: Add todo creation with validation
import { useState } from "react";
function TodoApp() {
const [todos, setTodos] = useState([]);
const [task, setTask] = useState("");
const handleSubmit = () => {
// Basic validation – prevent empty or whitespace‑only tasks
if (task.trim() === "") {
alert("Enter task to add");
return;
}
// Immutable update – create a new array with the new task
setTodos([...todos, task]);
// Reset input for better UX
setTask("");
};
return (
setTask(e.target.value)}
className="border rounded px-2 py-2 w-80 m-2"
/>
Add Task
{/* Render the list of todos */}
{todos.map((todo, idx) => (
{todo}
))}
);
}
학습 내용
- 제어된 입력 –
useState를 사용해 폼 입력을 관리하고, 입력 값을 React 상태가 완전히 제어하도록 했습니다. - 기본 검증 – 빈 문자열이나 공백만 있는 Todo가 추가되지 않도록 방지해 데이터의 정합성을 유지했습니다.
- 불변 상태 업데이트(배열) – 기존 배열을 변형하지 않고 스프레드 연산자(
[…todos, task])를 사용해 새 배열을 생성함으로써 React의 불변성 규칙을 지키고 올바른 재렌더링을 보장했습니다. - UX 향상을 위한 입력 초기화 – Todo를 추가한 뒤
setTask("")로 입력 필드를 비워 사용성을 높였습니다. - 동적 리스트 렌더링 –
map()을 활용해 Todo 목록을 동적으로 렌더링했습니다.