프로젝트
[리액트] 리액트로 ToDoList 만들기 - 토글 기능
ejunyang
2024. 5. 20. 19:29
UI 구현
Todo 추가 하기Todo 삭제 하기Todo 완료/취소 상태 변경하기 (진행중 ↔ 완료)
기능 구현
- 제목과 내용을 입력하고, [추가하기] 버튼을 클릭하면 Working에 새로운 Todo가 추가되고 제목 input과 내용 input은 다시 빈 값으로 바뀌도록 구성해주세요.
- [삭제하기] 버튼을 클릭하면 Working 또는 Done 에 있는 것과 상관없이 삭제처리가 되도록 해주세요.
- Todo의 isDone 상태가 true이면, 상태 버튼의 라벨을 취소, isDone이 false 이면 라벨을 완료 로 조건부 렌더링 해주세요.
- Todo의 상태가 Working 이면 위쪽에 위치하고, Done이면 아래쪽에 위치하도록 구현합니다.
- Layout의 최대 너비는 1200px, 최소 너비는 800px로 제한하고, 전체 화면의 가운데로 정렬해주세요.
- 컴포넌트 구조는 자유롭게 구현해보세요.
🍯 HINT
- 사용한 hook은 오직 useState
- 기능 구현을 위해 생성한 함수는 2개 입니다. onChangeHandler , onSubmitHandler
- 사용한 javascript 내장 메서드는 map, filter 입니다.
- todo의 initial state는 {id: 0, title: “”, body: “”, isDone: false} 입니다.
컴포넌트
TodoTemplate.jsx | 화면을 가운데에 정렬시켜주며, 일정 리스트를 보여줍니다. children으로 내부 JSX를 props로 받아 와서 렌더링해줍니다. |
TodoAdd.jsx | 할 일을 추가하는 컴포넌트 입니다. |
TodoList.jsx | todos 배열을 props로 받아 온 후, 이를 배열 내장 함수 map을 사용해서 여러 개의 TodoItem 컴포넌트로 변환하여 보여 줍니다. |
TodoItem.jsx | 진행중인 할 일 정보를 보여주는 컴포넌트입니다. todo 객체를 props로 받아 와서 상태에 따라 다른 스타일의 UI를 보여줍니다 |
CurrentDate.jsx | 현재 날짜를 알려주는 컴포넌트입니다. |
Icons.jsx | 배경에 꾸며주는 Sticker 요소를 보여주는 컴포넌트입니다. |
App.jsx
Todo의 isDone 상태가 true이면, 상태 버튼의 라벨을 취소, isDone이 false 이면 라벨을 완료 로 조건부 렌더링이 필요해서 토글 함수를 만들었다. 삭제 함수와 마찬가지로 id 값을 받아와서 처리하도록 했다.
map과 삼항연산자를 활용했다. map()으로 배열 순회를 돌면서 배열의 id와 사용자가 선택한 id 가 같다면, todo에 isDone 키의 값이 true -> false, false -> true 로 반전시켜주는 NOT 연산자를 사용해줬다. 같지 않다면 그대로 todo가 나오도록 해주었다.
const onToggle = (id) => {
setTodo(
todos.map((todo) =>
todo.id === id ? { ...todo, isDone: !todo.isDone } : todo
)
);
};
TodoList 에서 사용할 수 있게 props로 내려준다. 그리고 진행중인 리스트와 진행 완료된 리스트를 나누어서 완료된 리스트는 진행 중인 리스트 아래로 내려야 하기때문에 TodoList 를 두개 만들어주고 안에 들어가는 props 에 filter를 써서 조건부 렌더링이 되도록 해주었다.
const workingTodo = todos.filter((todo) => !todo.isDone);
const doneTodo = todos.filter((todo) => todo.isDone);
return (
<>
<TodoTemplate>
<CurrentDate todos={todos} />
<TodoList
key={todos.id}
todos={workingTodo}
onRemove={onRemove}
onToggle={onToggle}
/>
<TodoList
key={todos.id}
todos={doneTodo}
onRemove={onRemove}
onToggle={onToggle}
/>
<TodoAdd onInsert={onInsert} />
</TodoTemplate>
</>
);
TodoList.jsx
TodoItem에서 사용할 수 있도록 props를 내려주자.
const TodoList = ({ todos, onRemove, onToggle }) => {
return (
<div>
{todos.map((todo) => {
return (
<TodoItem
todo={todo}
key={todo.id}
onRemove={onRemove}
onToggle={onToggle}
/>
);
})}
</div>
);
};
TodoItem.jsx
isDone 이 true 일때 체크 아이콘은 ✔️ 상태를 유지하고, isDone 이 false 라면 O 체크를 지운 아이콘을 유지하도록 했다.
{isDone && (<IoCheckmark className="check" onClick={() => onToggle(id)} />)}
{!isDone && (<PiCircleLight className="check" onClick={() => onToggle(id)} />)}
이렇게 코드를 적고 실행을 했는데 오류가 생겼다. isDone is not defined.
코드를 확인해보니 구조할당분해에서 isDone을 빼먹어서 생긴 오류였다. isDone 을 넣어주니 정상적으로 작동하였다.
const { id, contents, isDone } = todo;