
0. configureStore로 리덕스 스토어 만들기 (/store/index.js)
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice";
export const store = configureStore({
reducer: {
counter: counterReducer,
},
});
1. redux 스토어 제공하기 (_app.js)
Provider로 감싸줍니다.
import "../styles/globals.css";
import { Provider } from "react-redux";
import { store } from "../store"; // 또는 import { store } from "../store/index.js";
function MyApp({ Component, pageProps }) {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
export default MyApp;
2. createSlice로 slice reducer 만들기
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
value: 0,
};
export const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
},
});
// Action creators are generated for each case reducer function
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
리덕스는 모든 state를 불변하게 업데이트했어야 했습니다. state그 자체를 수정하는게 아니라, 복사본을 만들어서 그 복사본을 업데이트하는 방식이었습니다. 그런데 리덕스툴킷의 createSlice와 createReducer API는 Immer를 자동으로 쓰고 있어요. 그래서 우린 그 state를 수정하는 것처럼(mutating update logic) 코드를 쓰면서도 실제로는 immutable update가 잘 되고 있답니다.
Redux requires that we write all state updates immutably, by making copies of data and updating the copies. However, Redux Toolkit's createSlice and createReducer APIs use Immer inside to allow us to write "mutating" update logic that becomes correct immutable updates.
Redux Toolkit allows us to write "mutating" logic in reducers. It doesn't actually mutate the state because it uses the Immer library, which detects changes to a "draft state" and produces a brand new immutable state based off those changes
3. useSelector, useDispatch 사용하기
(해당 예시에서는 increment만 불러왔음)
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
import { increment } from "../features/counter/counterSlice";
import { useDispatch, useSelector } from "react-redux";
export default function Home() {
const count = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
return (
<div className={styles.container}>
<button onClick={() => dispatch(increment())}>Add</button>
<p>{count}</p>
</div>
);
}
----
We specifically created Redux Toolkit to eliminate the "boilerplate" from hand-written Redux logic, prevent common mistakes, and provide APIs that simplify standard Redux tasks.
그래서 rtk가 제공하는 두가지 웅요한 API가 있다. 모든 리덕스앱에서 쓰이는 것들인데.
- configureStore
createStore보다 더 쉽다. createStore는 named options parameter가 필요하기 때문이다.
- createSlice
Immer 라이브러리를 사용해서 리듀서를 쓴다. state.value = 123 같이 스프레드 연산자 없이 mutating하는 식으로 코드를 작성할 수 있다.(물론 immutable하게 업데이트 해줌)
그리고 각 리듀서들마다 자동으로 액션 크리에이터 함수, 액션 타입을 만들어준다. (All of the action creators and action types are generated automatically, and the reducer code is shorter and easier to understand.)
=> 즉 코드를 더 간결하게 쓸 수 있다.
---
리덕스의 단점
1. 보일러플레이트 코드가 많이 필요하다.
- 액션타입
- 액션 생성함수
- 리듀서
리덕스에선 총 3가지 종류가 필요함.
리덕스에서 작성했을 때는 아래와 같다.
export const OPEN = 'msgbox/OPEN';
export const CLOSE = 'msgbox/CLOSE';
export const open = (message) => ({ type: OPEN, message });
const initialState = {
open: false,
message: '',
};
export default msgbox(state = initialState, action) {
switch (action.type) {
case OPEN:
return { ...state, open: true, message: action.message };
case CLOSE:
return { ...state, open: false };
default:
return state;
}
}
동일한 코드를 리덕스 툴킷을 사용했을 때는 아래와 같다. 리듀서, 액션타입, 액션 생성함수, 초기상태를 하나의 함수로 편하게 선언 할 수 있다. (이 라이브러리에선 이 4가지를 통틀어서 slice 라고 부릅니다.)
import { createSlice } from '@reduxjs/toolkit';
const msgboxSlice = createSlice({
name: 'msgbox',
initialState: {
open: false,
message: '',
},
reducers: {
open(state, action) {
state.open = true;
state.message = action.payload
},
close(state) {
state.open = false;
}
}
});
export default msgboxSlice;
createSlice를 써서 각 리듀서들마다 자동으로 액션 크리에이터 함수, 액션 타입을 만들어주고 있다.
(All of the action creators and action types are generated automatically, and the reducer code is shorter and easier to understand.)
참고 및 코드: https://ridicorp.com/story/how-to-use-redux-in-ridi/
2. 불변성을 지키기 번거롭다.
리덕스에서는
- ...state 식으로 스프레드 연산자 사용해야 한다.
- 혹은 immer를 사용해 간소화 할 수 있다.
리덕스 툴킷을 이용하면 immer를 따로 설치할 필요 없이 자동으로 사용됩니다. mutable하게 코드를 작성해도 불변성을 지키면서 업데이트 가능하다는 거죠.
---
리덕스 공식 문서에서도 리덕스 툴킷을 사용하길 권장하고 있습니다.
