Group Study (2022-2023)/React.js

[React] 3주차 스터디 - (심화) Pure Redux(2): To-do List

smjan27 2022. 10. 30. 16:05

1. Vanilla ToDo

* 기능: 내용을 작성하고 Add 버튼을 누르면 ul 태그가 아래에 추가되는 투두리스트

index.html

<h1>To Dos</h1>
  <form>
    <input type="text" placeholder="Write to do" />
    <button>Add</button>
  </form>
<ul></ul>

index.js

import { createStore } from "redux";

const form = document.querySelector("form");
const input = document.querySelector("input");
const ul = document.querySelector("ul");

const ADD_TODO = "ADD_TODO";
const DELETE_TODO = "DELETE_TODO";

// Reducer: modify state
const reducer = (state = [], action) => {
  // Action
  console.log(action);
  switch (action.type) {
    case ADD_TODO:
      return [];
    case DELETE_TODO:
      return [];
    default:
      return state;
  }
};

// Store: data area
const store = createStore(reducer);

// sending message
const onSubmit = e => {
  e.preventDefault();
  const toDo = input.value;
  input.value = "";
  store.dispatch({ type: ADD_TODO, text: toDo });
};

form.addEventListener("submit", onSubmit);

 

2. State Mutation

  • state is immutable (변경 불가)
  • 기존 배열에 직접 값을 추가할 수 없음
// Reducer: modify state
const reducer = (state = [], action) => {
  // Action
  switch (action.type) {
    case ADD_TODO:
      return return [{ text: action.text, id: Date.now() }, ...state]; // 기존 배열에 직접 값을 추가하지 말기! state is immutable(변경 불가)
    case DELETE_TODO:
      return [];
    default:
      return state;
  }
}

 

3. Delete ToDo

  • store.dispatch({ type: ADD_TODO, text })을 수행하는 함수 addToDo 생성
  • 삭제 기능을 구현하기 위해 투두를 paint하는 함수 paintToDos 생성
  • 투두 리스트를 삭제하는 함수 deleteDoDo 생성
  • state를 mutate하지 않도록 array.filter() 함수 사용하여 새로운 배열 생성
import { createStore } from "redux";

const form = document.querySelector("form");
const input = document.querySelector("input");
const ul = document.querySelector("ul");

const ADD_TODO = "ADD_TODO";
const DELETE_TODO = "DELETE_TODO";

const addToDo = (text) => {
  return {
    type: ADD_TODO,
    text,
  };
};

const deleteToDo = (id) => {
  return {
    type: DELETE_TODO,
    id,
  };
};

// Reducer: modify state
const reducer = (state = [], action) => {
  // Action
  switch (action.type) {
    case ADD_TODO:
      return [{ text: action.text, id: Date.now() }, ...state]; // 기존 배열에 직접 값을 추가하지 말기! state is immutable(변경 불가)
    case DELETE_TODO:
      return state.filter((toDo) => toDo.id !== action.id); // 삭제하고자 하는 id를 갖고 있지 않은 배열만 필터링
    default:
      return state;
  }
};

// Store: data area
const store = createStore(reducer);

const dispatchAddToDo = (text) => {
  store.dispatch(addToDo(text));
};

const dispatchDeleteToDo = (e) => {
  const id = parseInt(e.target.parentNode.id); // 삭제할 부모 노드의 id
  store.dispatch(deleteToDo(id));
};

const paintToDos = () => {
  const toDos = store.getState();
  ul.innerHTML = "";
  toDos.forEach((toDo) => {
    const li = document.createElement("li");
    const btn = document.createElement("button");
    btn.innerText = "DEL";
    btn.addEventListener("click", dispatchDeleteToDo);
    li.id = toDo.id;
    li.innerText = toDo.text;
    ul.appendChild(li);
    li.appendChild(btn);
  });
};

store.subscribe(() => console.log(store.getState()));
store.subscribe(paintToDos);

// sending message
const onSubmit = (e) => {
  e.preventDefault();
  const toDo = input.value;
  input.value = "";
  dispatchAddToDo(toDo);
};

form.addEventListener("submit", onSubmit);

 

4. Conclusions

  • dispatchAddToDo, dispatchDeleteToDo: action을 dispatch하기 위한 용도의 함수
  • addToDo, deleteToDo: reducer 함수에 전달되는 action 객체를 리턴
  • state는 변경할 수 없음(immutable): 여기서는 toDos 배열을 직접 수정하지 않고 새로운 배열 생성
  • 배열의 filter 함수: test 조건을 통과한 요소만 남겨서 새로운 배열 생성
  • store.subscribe(paintToDos): ToDo의 변화에 맞추어 배열을 repainting