본문 바로가기
학원에서 배운 것/React

KDT 5th 웹개발자 입문 수업 43일차 - 1

by 쿠리의일상 2023. 4. 5.

Todo List 마저 구현하기

리듀서의 DONE 동작 구현

list 이외의 초기 state 값은 그대로 전달 되어야 하므로 전개 연산자를 꼭 사용해줘야 한다.

컴포넌트에서 전달 받은 id 값과 동일한 객체를 찾은 다음, 해당 객체의 done 항목을 true 로 변경해준다.

 

배열의 map() 메서드는 배열의 모든 값을 순회하면서 배열의 값을 return 된 값으로 변경해주기에 해당 메서드를 사용해준다.

//reducer
export default function todo(state = initState, action) {
  switch (action.type) {
    case CREATE:
      return {
        ...state,
        todoList: [
          ...state.todoList,
          {
            id: action.payload.id,
            text: action.payload.text,
            done: false,
          },
        ],
        nextId: action.payload.id + 1,
      };
    case DONE:
      return {
        ...state,
        todoList: state.todoList.map((e) => {
          if (e.id === action.id) {
            return {
              ...e,
              done: true,
            };
          } else {
            return e;
          }
        }),
      }; 
    default:
      return state;
  }
}

 

만들어준 리듀서를 컴포넌트에서 완료된 목록의 id 값을 받고 해당 목록의 done 키의 값을 true 해준다.

export default function TodoList() {
  const list = useSelector((state) => state.todo.todoList).filter(
    (e) => !e.done,
  );
  const inputRef = useRef('');
  const dispatch = useDispatch();

  const addTodo = () => {
    dispatch(
      create({
        id: list.length,
        text: inputRef.current.value,
      }),
    );
    inputRef.current.value = '';
  };

  return (
    <section>
      <h2>할일 목록</h2>
      <div>
        <input type="text" ref={inputRef} />
        <button onClick={addTodo}>추가</button>
      </div>
      <ul>
        {list.map((e) => {
          return (
            <li key={e.id}>
              {e.text}
              <button onClick={() => dispatch(done(e.id))}>완료</button>
            </li>
          );
        })}
      </ul>
    </section>
  );
}
export default function DoneList() {
  const list = useSelector((state) => state.todo.todoList).filter((e) => {
    return e.done === true;
  });

  return (
    <section>
      <h2>완료된 목록</h2>
      <ul>
        {list.map((e) => (
          <li key={e.id}>{e.text}</li>
        ))}
      </ul>
    </section>
  );
}

 

같은 키를 가진 경우

리스트 요소의 key 값은 고유해야 하므로 발생하는 경고

즉, todoList 에서 할일을 추가할 때 store 에서 받아온 list 의 length 값을 넘기고 -> 이미 완료를 하면 리스트의 길이가 짧아지고, 새로 생성되는 <li> 요소는 이전의 key 와 동일한 값을 가지게 되므로 발생!

 

할일 목록 id 를 목록의 순번으로 부여하고 있으므로 해당 순번을 store 에서 전역으로 관리하여 문제를 해결할 수 있다.

let counts = initState.todoList.length;
initState['nextId'] = counts;
switch (action.type) {
    case CREATE:
      return {
        ...state,
        todoList: [
          ...state.todoList,
          {
            id: action.payload.id,
            text: action.payload.text,
            done: false,
          },
        ],
        nextId: action.payload.id + 1,
      };

 

리스트의 길이로 key 를  관리하는 것이 아닌, nextId 값을 todo.js 모듈에서 처리 후 받아준다.

  const nextId = useSelector((state) => state.todo.nextId);

  const addTodo = () => {
    dispatch(
      create({
        id: nextId,
        text: inputRef.current.value,
      }),
    );
    inputRef.current.value = '';
  };

 

key 값을 어떻게 처리할지가 중요한 것 같다.