<숙련주차 시험>
어떤부분이 문제였고 어떻게 해결했는지에 대해 소스코드를 포함해서 자세한 설명을 적어주세요.
<Form.jsx - dispatch 작업 추가>
아이템을 추가하는 액션을 디스패치 해야 할 때, 먼저 액션객체를 리듀서로 보내기 위해 useDispatch를 import 해주고, dispatch 변수를 생성하는 코드를 추가해준다. (const dispatch = useDispatch();)
‘추가하기’ 버튼을 눌렀을때 추가가 되어야하기 때문에 onSubmitHandler() 안에서 Action Creator ‘addTodo()’를 dispatch 후, input값이 todo에 새롭게 추가되어야하기 때문에 그 인자에 {...todo, id} 넣어준다. todo는 todos에 추가될 것이고, id는 payload를 통해 인자값으로 전달될 것이다.
(dispatch( addTodo({...todo, id}) );)
리듀서는 dispatch를 통해 전달받은 addTodo로 스위치문 안의 해당 case를 찾아 해당 state로 리턴해 입력값이 추가된 새로운 state로 업데이트 하게된다.
<todos.js - 리듀서의 ADD_TODO case에 요소 추가>
input으로 추가한 데이터가 화면에 렌더링되긴 하는데, initialState로 설정된 아이템이 사라지고 그 자리에 대체된다. 리듀서에 payload로 state 값을 변경해주긴 하는데, 현재 상태에서 todos 배열에 입력된 값을 추가해주는 코드가 누락되어있다.
리듀서 안 ‘ADD_TODO’ 케이스 return 값에 todos: [action.payload] 부분을 todos: [...state.todos, action.payload]로 변경해준다.
<todos.js - 리듀서에 DELETE_TODO case 추가>
리스트에서 ‘삭제하기’ 버튼을 클릭하면 onDeleteTodo() 이벤트가 발생하는데, deleteTodo 액션 크리에이터 dispatch문까지 잘 써놓고, 정작 리듀서에 DELETE_TODO case가 누락되어있다. 액션 크리에이터를 참고하여 DELETE_TODO로 type을 맞추고, 삭제된 state로 업데이트할 코드를 작성한다. filter() 메소드를 사용해 todos안에서 payload로 받아온 인자와 일치하지 않는 todo의 id값을 가진 값들만 불러오면 삭제기능을 구현할 수 있다.
<< 추가된 코드 >>
case DELETE_TODO:
return {
...state,
todos: state.todos.filter((todo) => todo.id !== action.payload),
};
<Detail.jsx - useEffect문 추가>
getTodoByID 액션크리에이터와 리듀서는 존재하는데, 정작 상세페이지 코드에 todo의 id와 일치하는 데이터를 불러오는 코드가 없다. 리듀서 타입 GET_TODO_BY_ID 가 todos의 todo id와 일치하는 payload(인자값)을 찾는 동작이기 때문에, action.payload에 받아올 값을 넘겨주어야 한다.
이를 위해 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 useEffect 훅을 써준다. 의존성배열 [dispatch, id]가 변경될 때마다 getTodoById()에 id값을 전달해주는 dispatch문을 추가해준다. dispatch, id 두가지 상태값을 참조하면서 dispatch문을 실행하게 된다.
<< 추가된 코드 >>
useEffect(() => {
dispatch(getTodoByID(id));
}, [dispatch, id]);
<List.jsx - 완료된 카드 부분 Link 수정>
현재 한개의 완료된 카드의 상세보기를 누르면 해당 카드의 상세보기 내용이 아니라, todo 배열의 첫번째 데이터 상세보기가 렌더링된다. 이는 List.jsx의 todo.isDone만 map()함수로 불러오는 ‘Done..!’ 부분을 보면 map()함수 인자값으로 todo와 index를 받아오고, 상세보기 Link가 /${index}
로 설정되어있는 것을 볼 수 있다. 상세보기를 클릭한 todo의 id값과 일치하는 상세보기 페이지가 아니라, todos의 index값으로 설정되어있기 때문에 배열의 첫번째 값이 보여지는 것이다. 완료된 카드를 2개 이상으로 추가하면 아예 값을 불러오지 못한다. 이것은 todo.isDone일때의 상세보기 Link를 todo.id로 설정해주면 해당 id의 상세보기 페이지로 잘 이동하는 것을 볼 수 있다. 쓸모 없어진 index 인자는 삭제해준다.
<< 변경된 코드 >>
1. todos.map((todo, index) =>) -> todos.map((todo) =>)
2. <StLink to={/${index}
}> -> <StLink to={/${todo.id}
}>
<List.jsx - 완료된 카드 부분 취소 버튼 수정>
onToggleStatusTodo()와 연결된 toggleStatusTodo, TOGGLE_STATUS_TODO는 잘 구현되어있는데도 취소 기능이 작동하지 않아 살펴보니, todo.isDone 일 때 취소/완료 부분에 onToggleStatusTodo 이벤트 리스너에 클릭된 todo의 id값이 들어가지 않고 있었다. 이벤트 리스너를 보면 id값이 필수로 들어가야 action이 dispatch될 수 있기 때문에 화살표 함수의 형태로 <StButton onClick={() => onToggleStatusTodo(todo.id)} 로 수정해주었다.
<< 변경된 코드 >>
onClick={onToggleStatusTodo} -> onClick={() => onToggleStatusTodo(todo.id)}