처음엔 todo의 개념 자체가 헷갈렸음.
그래서 구조를 이렇게 잡음.
const [todos,setTodos] = useState([]);
그리고 단순 문자열이 아니라 객체로 저장하도록 변경함.
{
text: "공부하기"
compleated: false
}
👉 이유 : 완료 상태까지 관리해야 하기 때문.
처음에 이렇게 생각했다.
todos.push(newTodo);
setTodos(todos);
하지만 React는 기존 배열을 직접 수정하는 걸 좋아하지 않는다.
React는 상태가 바뀌었는지 확인할 때
값을 깊게 비교하지 않고 참조값(주소)을 본다.
push는 기존 배열을 수정하기 때문에
주소가 그대로다.
그래서
setTodos([...todos, newTodo]);
👉 기존 배열을 복사해서
👉 새로운 배열을 만들어 넣어준다.
완료 체크 기능을 구현하면서 또 한 번 막혔다.
const handleToggle = (index) => {
setTodos(
todos.map((todo, i) =>
i === index
? { ...todo, completed: !todo.completed }
: todo
)
);
};
여기서 이해한 것 :
기존 객체를 복사한 뒤
completed 값만 덮어쓰기 위해서.
{ ...todo, completed: !todo.completed }
👉 기존 내용 유지 + 특정 속성만 변경
setTods(todos.filter((_, i) => i !== index));
filter는
👉 특정 조건을 만족하는 것만 남겨서
👉 새 배열로 반환한다.
그래서 삭제할 index만 제외하면 된다.
처음엔 onKeyDown과 버튼 클릭이 동시에 실행되어
중복 추가 문제가 발생했다.
해결 방법 :
<form onSubmit={handleAdd}>
그리고
e.preventDefault();
👉 Enter는 원래 form 제출 동작이기 때문에
form + onSubmit 구조가 가장 안정적이란걸 알게됨.
이걸 통해 이벤트 흐름도 이해하게 되었음.
✔ React는 직접 수정하면 안된다
✔ 항상 "새 배열/새 객체"를 만들어야한다
✔ spread 문법은 복사
✔ map은 수정
✔ filter는 삭제
✔ form + onSubmit이 Enter 처리의 정석
🐙 GitHub Repository
👉 https://github.com/wjdtor2-design/Frontend-portfolio
📝 Velog Study Log