TIL_ Redux 사용하여 todo 리스트 만들기

이고운·2022년 11월 10일
0

Redux 실습

목록 보기
2/2

1. 개요

이번에는 좀 더 심화학습으로 pure redux를 사용한 투두리스트를 만들어 봤음.

2. 코드 설명

1) 기본 작업하기 javascript

시작은 기존 javascript 를 이용하여 todo리스트를 만들어줌.

<index.html>
<h1>To Dos</h1>
    <form>
      <input type="'text" placeholder="write to do" />
      <button>Add</button>
    </form>
    <ul></ul>

<index.js>
const form = document.querySelector("form");
const input = document.querySelector("input");
const ul = document.querySelector("ul");

const createToDo = (toDo) => {
  const li = document.createElement("li");
  li.innerText = toDo;
  ul.appendChild(li);
};
const onSubmit = (e) => {
  e.preventDefault();
  const toDo = input.value;
  input.value = "";
  createToDo(toDo);
};
form.addEventListener("submit", onSubmit);

역시나 이렇게 하면 우리 application은 data를 가지고 있지 않음
단순 html수정에 불과함. 데이터를 저장하는 것이 아님.

2) Redux사용하여 변경

(1) 프로젝트 셋업 : reducer와 dispatch를 이용하여 기본 redux 작업해줌.

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 reducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [];
    case DELETE_TODO:
      return [];
    default:
      return state;
  }
};
const store = createStore(reducer);

const onSubmit = (e) => {
  e.preventDefault();
  const toDo = input.value;
  input.value = "";
  store.dispatch({ type: ADD_TODO, text: toDo });
};
form.addEventListener("submit", onSubmit);

여기서 중요하게 생각할 것은 state.push(action.text)를 할 게 아니라 (mutation ❌❌) 새로운 값을 return 하는 것.

(2) addToDo 함수 만들기 -새로운 array

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";


//아래에 있던 dispatch({type: ADD_TODO, text})를 따로 함수로 만듬
const addToDo =(text)=>{
  return {
  type: ADD_TODO,
  text
 }
}  

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

const reducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      //return state.push(action.text) 이게 아니라 새로운 배열을 return 해야함.
      //...state를 뒤로 보내서 array 가 보이는 방식을 수정할 수 있음.
      return [{ text: action.text, id: Date.now() }, ...state]; //새로운 object로 array를 만든 것임.
    case DELETE_TODO:
      return [];
    default:
      return state;
  }
};
const store = createStore(reducer);

store.subscribe(() => {
  console.log(store.getState());
});

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

//parentNode를 알아야함. 왜냐면 삭제할 todo의 id가 필요하기 때문
const dispatchDeleteToDo = (e) => {
  const id = e.target.parentNode.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;
    li.appendChild(btn);
    ul.appendChild(li);
  });
};

store.subscribe(paintToDos);

const onSubmit = (e) => {
  e.preventDefault();
  const toDo = input.value;
  input.value = "";
  addToDo(toDo);
};
form.addEventListener("submit", onSubmit);

여기까지하면 삭제 버튼을 눌렀을때 리스트가 전부 삭제 됨.
삭제 버튼을 눌렀을 때 mutation한 방법 (splice) 말고 ❌ 다른 방법을 생각해야하는데, 이 때 filter 메소드 이용한다.
(공식문서에 보면 filter메소드에 대해 '테스트를 통과한 모든 element들로 새로운 array를 만든다고 써있음)

(3) DeleteToDo - filter함수

const reducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO :
      return [{text: action.text, id: Date.now()}, ...state]
    case DELETE_TODO :
      return state.filter(toDo => toDo.id !== action.id)
    default :
      return state;
      
 //문자열을 숫자로 바꿔주기 위해 parseInt 사용 (HTML로 받아오는 id는 string 타입일 것이기 때문)    
 const dispatchDeleteToDo = (e) => {
  const id = parseInt(e.target.parentNode.id);
  store.dispatch(deleteToDo(id));
};

      ````
### 3) 결과 코드
```javascript
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,
  };
};
const reducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [{ text: action.text, id: Date.now() }, ...state];
    case DELETE_TODO:
      return state.filter((toDo) => toDo.id !== action.id);
    default:
      return state;
  }
};
const store = createStore(reducer);

store.subscribe(() => {
  console.log(store.getState());
});

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

const dispatchDeleteToDo = (e) => {
  const id = parseInt(e.target.parentNode.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;
    li.appendChild(btn);
    ul.appendChild(li);
  });
};

store.subscribe(paintToDos);

const onSubmit = (e) => {
  e.preventDefault();
  const toDo = input.value;
  input.value = "";
  dispatchAddToDo(toDo);
};
form.addEventListener("submit", onSubmit);

3. 최종 정리

profile
자 이제 시작이야~ 내 꿈을~ 내 꿈을 위한 여행~~🌈

0개의 댓글