이번에는 바닐라JS에 리덕스를 이용하여 투두리스트를 만들어보자!
import { legacy_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) => {
console.log(action);
switch (action.type) {
case ADD_TODO:
return [];
case DELETE_TODO:
return [];
default:
return state;
}
};
const store = legacy_createStore(reducer);
const onSubmit = e => {
e.preventDefault();
const toDo = input.value;
input.value = "";
store.dispatch({ type: ADD_TODO, text: toDo });
};
form.addEventListener("submit", onSubmit);
우리가 이전에 배웠던 방식으로 이렇게 만들어주었다.
이렇게 해주고 입력창에 "투두투두리덕스"라고 입력한 후 Add버튼을 클릭해보았다.
콘솔창을 열어보면
text로 잘 들어오는 것을 확인👌👌👌
즉, 우리는 이제 새로운 투두와 함께 array를 리턴할 수 있다.
state 수정을 위해서는
mutate
(변형)하는게 아니라,
새로운 state를 리턴해야한다.🔊🔊
그래서 우리는 만약 누군가 투두를 add한다면?
return state.push(action.text);
하는 것이 아니라
(✍️ 위의 경우 state를 mutate하는 것이겠지,,)
return [...state, {text:action,text}];
state를 mutate하면 안된다는 것은 redux의 기본이다!
꼭 기억하자
const paintToDos = () => {
const toDos = store.getState();
toDos.forEach(toDo=>{
const li = document.createElement("li");
li.id=toDo.id;
li.innerText = toDo.text;
ul.appendChild(li);
});
};
store.subscribe(paintToDos);
투두를 삭제하기 위해서는 투두들을 paint해야함
그래서 위 코드와 같이 store에 다른 function(paintToDos
)을 subscribe 해줘야함!
그런데 이렇게 해주면 add할때마다 list가 repainting가 되어 계속 같은 값이 중복되어 출력되는 경우가 생긴다.
왜그러냐면..
store가 바뀔 때마다 매번! 모든 것을 repaint하고 있기 때문.
(const toDos = store.getState();
)
ul.innerHTML="";
innerHTML을 추가해주면 문제는 해결된다.
일단 투두마다 삭제버튼이 있어야겠지? 그걸 만들어준다.
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",deleteToDo);
li.id=toDo.id;
li.innerText = toDo.text;
li.appendChild(btn);
ul.appendChild(li);
});
};
요런식으로ㅇㅇ,, 그리고 이제 저 btn의 eventlistner에 연결해놓은 함수 deleteToDo
를 작성해주어야함!
일단 우리는 delete를 할 때 어떤 투두의 버튼이 눌렸는지 그 정보를 받아와야한다!
지우고싶은 li의 id(우리가 미리 설정해준!!)로 받아올 것임
const addToDo = (text) => {
return {
type: ADD_TODO,
text
};
};
const deleteToDo = id =>{
return {
type:DELETE_TODO,
id
};
};
...
const dispatchAddToDo = (text)=>{
store.dispatch(addToDo(text));
};
const dispatchDeleteToDo = (e) =>{
const id = e.target.parentNode.id;
store.dispatch(deleteToDo(id));
}
...
이롷게~~~ 해주자
dispatch
와 action
리턴하는 부분 나눠주었음
filter()는 테스트를 통과한 모든 element들로 새로운 array를 만듦.
case DELETE_TODO:
return state.filter(toDo => toDo.id !== action.id);
즉, 이렇게 해주면 우리가 원하는대로 DEL버튼을 클릭한 투두만 리스트에서 삭제된다.
state를 변형시키면 안된다는 것을 명심하자~!!!
import { legacy_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
};
};
const reducer = (state = [], action) => {
switch (action.type) {
case ADD_TODO:
const newToDoObj = {text:action.text, id:Date.now()};
return [newToDoObj, ...state];...state];
case DELETE_TODO:
const cleaned = state.filter(toDo => toDo.id !== action.id);
return cleaned;
default:
return state;
}
};
const store = legacy_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);