DH의 개발 공부로그
[Redux] Redux Example - 바닐라 자바스크립트 투두리스트 만들어보기! 본문
프로젝트 설명
리덕스를 공부하는 이유가 리덕스를 이용해서 리액트에서의 상태관리를 보다 편하게 작업을 하기 위해서였는데,
공부를 해보니 꼭 리덕스가 리액트와 함께 사용이 안되어도 가능하다는 것을 알게 되었습니다.
그래서 우선 자바스크립트에서 사용하는 법을 먼저 연습해보고 리액트에서 사용법을 공부해야겠다 생각을 하여
자바스크립트 투두리스트를 만들어 보았습니다.
폴더구조
yarn
과 vite
로 작업을 하였고 폴더 구조는 다음과 같이 간단하게 작업을 했습니다.
index.html - body부분
<body>
<h1>To Dos</h1>
<form>
<input type="text" name="toDo" placeholder="할 일을 작성 해주세요.">
<button>Add</button>
</form>
<ul></ul>
<script type="module" src="/src/index.js"></script>
</body>
index.js
1. 변수 선언 및 form 이벤트 추가
우선 변수들을 선언하고 onSubmit
함수를 만들어 주었습니다.
const $form = document.querySelector('form');
const $input = document.querySelector('input);
const $toDolist = document.querySelector('ul');
const onSubmit = (e) => {
e.preventDefault()
const toDoValue = $input.value
$input.value = ''
addToDo(toDoValue) // 입력한 값을 추가해주는 함수
}
$form.addEventListener('submit', onSubmit)
2. Redux 추가
저는 yarn
을 이용해서 작업을 했기 때문에 다음의 코드로 리덕스를 설치했습니다.
$ yarn add redux
그리고 우선 스토어와 리듀서 함수를 만들어 주었습니다.
const reducer = (state, action) => {
console.log(state, action)
if (state === undefined) {
return { toDoList: [] }
}
}
const store = createStore(reducer)
스토어를 생성하면서 reduce
함수도 실행이 되기 때문에 초기 state
값 설정을 조건문을 이용해서undefined
일 시 초기값을 리턴하도록 했습니다.
3. 리스트 추가하기
const ADD_TODO = "ADD TODO";
const reducer = (state, action) => {
if (state === undefined) {
return {
toDoList: []
}
}
switch(action.type) {
case ADD_TODO: {
const newToDoList = [{ text: action.text, id: Date.now() }, ...state.toDoList]
const newState = Object.assign({}, state, {
toDoList: newToDoList
})
return newState
}
default: {
return state
}
}
}
const addToDo = (text) => {
store.dispatch({ type: ADD_TODO, text })
}
위에 onSubmit
함수에서 호출한 addToDo
함수로 스토어에 디스패치하도록 하였으며,
이 디스패치를 받은 리듀서에서 switch
문으로 action.type
을 확인하도록 하였습니다.
타입이 ADD_TODO
일 경우 우선 불변성을 지키기 위하여 기존의 toDoList
배열을 spread 연산자
로 복사하고,Object.assign
로 기존의 값인 객체를 복사하여 추가한 후 복사한 값을 리턴해주었습니다.
4. UI 그리기
const paintTodo = () => {
const state = store.getState();
$toDolist.innerHTML = '';
// 두번째로 추가할 때 기존에 있던 태그가 반복이 되기 때문에 초기화하기
state.toDoList.map((toDo) => {
const li = document.createElement('li'); // <li>태그 만들기
const btn = document.createElement('button') // <button>태그 만들기
btn.innerText = 'Del';
btn.addEventListener('click', deleteTodo) // 삭제 이벤트 추가
li.id = toDo.id; // 삭제를 위해 추가하는 iD 값
li.innerText = toDo.text;
li.appendChild(btn)
$toDolist.appendChild(li);
});
}
store.subscribe(paintTodo)
getState()
함수로 state
값을 가져와서 반복문을 통해 li 태그를 만들어 주었고,
리덕스의 subscribe()
내장함수를 이용해서 state
가 바뀌면 다시 함수를 호출 하도록 해주었습니다.
5. 리스트 삭제
// reducer에서 action.type이 DELETE_TODO인 경우
case DELETE_TODO : {
const newToDoList = state.toDoList.filter((toDo) => {
return toDo.id !== action.id
})
const newState = Object.assign({}, state, {
toDoList: newToDoList
})
return newState
}
const deleteTodo = (e) => {
const id = e.target.parentNode.id
store.dispatch({ type: DELETE_TODO, id: parseInt(id) })
}
삭제 역시 마찬가지로 li 태그에 추가해둔 id 값을 디스패치로 보내주고,filter
를 이용해서 id 값을 비교하여 새로운 배열을 만들어 주었습니다.
그후 역시나 객체를 복사해 새로운 객체를 리턴하였습니다.
6. 로컬스토리지에 추가해 저장하기
const setLocalStorage = (toDos) => {
const toDoList = JSON.stringify(toDos)
window.localStorage.setItem('ToDos', toDoList)
}
const paintTodo = () => {
// const state = store.getState();
const localToDosList = JSON.parse(window.localStorage.getItem('ToDos'))
$toDolist.innerHTML = '';
localToDosList.map((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)
$toDolist.appendChild(li);
});
}
setLocalStorage
함수를 만들어서 각각의 case에 추가를 해주었고,paintTodo
에서 JSON.parse(window.localStorage.getItem('ToDos'))
로 로컬스토리지의 값을 불러와서 map
함수를 돌리도록 하였습니다.
결과
'Redux' 카테고리의 다른 글
[Redux] Redux Toolkit - configureStore, createSlice 사용하기 (0) | 2023.03.22 |
---|---|
[Redux, React] React-Redux - useSelector, useDispatch로 state에 접근하기! (0) | 2023.03.16 |
[Redux] Redux에 사용되는 키워드 알아보기! (0) | 2023.03.08 |