앞서 리덕스 사용 방법에 대해서 공부해봤습니다.
그렇다면Redux Toolkit
은 무엇일까요?
리덕스 툴킷도 리덕스입니다. 그렇다면 리덕스 툴킷은 왜 나오게 된걸까요?
현재 리덕스 공식문서에서도 기본적으로 리덕스 툴킷을 추천하고 있습니다.
리덕스 공식문서에는 아래와 같이 소개하고 있습니다.
'Redux Toolkit은 Redux 로직을 작성하기 위해 저희가 공식적으로 추천하는 방법입니다. RTK는 Redux 앱을 만들기에 필수적으로 여기는 패키지와 함수들을 포함합니다. 대부분의 Redux 작업을 단순화하고, 흔한 실수를 방지하며, Redux 앱을 만들기 쉽게 해주는 모범 사례를 통해 만들어졌습니다.'
- 리덕스 공식문서
결국 리덕스 툴킷은 기존 리덕스를 조금 더 쉽게 안정적으로 만들어지기 위해 나온것으로 보입니다.
이번에는 리덕스 툴킷을 통해 기존 리덕스를 변경해보도록 하겠습니다.
리덕스 툴킷을 설치하게 되면 기본적으로 redux-devtools-extension
로 라이브러리가 설치되어 따로 설치할 필요가 없습니다.
// 리덕스 라이브러리 다운로드
$ npm install @reduxjs/toolkit react-redux
기존 리덕스에서 사용하던 방법과 동일합니다.
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import App from "App";
import store from "app/store";
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
리덕스 툴킷에서는 app
폴더를 안에 store.js
파일을 통해 하나의 스토어 정의를 하도록 하고 각각의 features
폴더 아래에 리덕스가 사용되는 컴포넌트와 --slice.js
파일을 통해 리덕스 상태를 관리하고 있습니다.
기존에 createStore에서 configureStore
로 변경이 되었으며 객체 형태의 인자에는 reducer가 필수
로 존재해야합니다.
// app/store.js
import { configureStore } from "@reduxjs/toolkit";
import todoSlice from "features/todo/todoSlice";
export const store = configureStore({
reducer: {
todo: todoSlice,
},
});
리덕스 툴킷에는 createAction
, createReducer
등 다양한 API를 제공하고 있지만 저는 createSlice
를 사용하도록 하겠습니다.
slice
는 리듀서와 action creator 등의 기능들을 제공해주는 객체입니다.
slice
를 사용하게 될 경우 기존의 inital state 와 액션, 리듀서를 하나로 통합하여 만들수 있으며 리덕스 툴킷에는 기본적으로 immer
라는 라이브러리가 내장되어있어 기존에 불변성을 위해 사용되는 concat, map, filter 등을 사용하여 불변성을 관리할 필요없이 알아서 관리를 해주기 때문에 아래와 같이 상태를 직접 변경해도 됩니다.
// features/todo/todoSlice.js
import { createSlice } from "@reduxjs/toolkit";
const INITIAL_STATE = {
todos: [{ id: 1, text: "첫번째", done: false }],
};
export const slice = createSlice({
name: "todo",
initialState: INITIAL_STATE,
reducers: {
todoInsert: (state, action) => {
const insertId =
Math.max(0, ...state.todos.map((todo) => Number(todo.id))) + 1;
const insertText = action.payload;
state.todos.push({ id: insertId, text: insertText, done: false });
},
todoRemove: (state, action) => {
const deleteId = action.payload;
const index = state.todos.findIndex((todo) => todo.id === deleteId);
state.todos.splice(index, 1);
},
todoUpdate: (state, action) => {
const { id: updateId, text: updateText } = action.payload;
const index = state.todos.findIndex((todo) => todo.id === updateId);
state.todos[index].text = updateText;
},
todoToggle: (state, action) => {
const toggleId = action.payload;
const index = state.todos.findIndex((todo) => todo.id === toggleId);
state.todos[index].done = !state.todos[index].done;
},
},
});
export const { todoInsert, todoRemove, todoUpdate, todoToggle } = slice.actions;
export const selectTodo = (state) => state.todo;
export const selectTodos = (state) => state.todo.todos;
export default slice.reducer;
기존 사용과 마찬가지로 useSelector
, useDispatch
를 통해 상태를 변경 할 수 있습니다.
2, 3과 같이 slice
에서 따로 상태를 정의하여 useSelect
를 통해 사용할 수 있습니다.
import { useSelector, useDispatch } from "react-redux";
import { todoInsert } from "./todoSlice";
import { selectTodo, selectTodos } from "./todoSlice";
export default function Components() {
1. const { todos } = useSelector((state) => state.todo);
2. const { todos } = useSelector(selectTodo);
3. const todos = useSelector(selectTodos);
const dispatch = useDispatch();
const handleDispatch = () => {
dispatch(todoInsert({ payload }));
};
}
리덕스 공식문서(리덕스 툴킷)
https://ko.redux.js.org/redux-toolkit/overview
리덕스 툴킷 공식문서
https://redux-toolkit.js.org
화해 블로그 리덕스 툴킷 http://blog.hwahae.co.kr/all/tech/tech-tech/6946
👉 깃주소
https://github.com/kim-gunwoo/redux-exam