React 71장 - Redux-Toolkit (1) redux 비교하기
포스트
취소

React 71장 - Redux-Toolkit (1) redux 비교하기

React

1
npm i redux react-redux @reduxjs/toolkit

Redux-Toolkit (RTK)

  • Next.js에서 Redux-Toolkit을 사용하기 전에 자세히 알아보자
  • 기존의 리덕스를 사용 시, 상태 관리를 할수록 코드가 많아지고 복잡해지는 문제점을 해결한 것이다.

Redux vs Redux-Toolkit

Redux

  • reducer를 구현할 때마다 type이름을 적어야하며, switch/if문을 반복적으로 사용해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// store.js
import { createStore } from 'redux';

const reducer = (state = { counter: 0 }, action) => {
  switch(action.type) {
    case 'increment':
      return { counter: state.counter + 1 }
    case 'decrement':
      return { counter: state.counter - 1 }
    default:
      return state
  }
}

const store = createStore(reducer);

export default store;

// App.jsx
import { useSelector, useDispatch } from 'react-redux'

function App() {
  const counter = useSelector((state) => state.counter);
  const dispatch = useDispatch();

  const increment = () => {
    dispatch({ type: 'increment' })
  }

  const decrement = () => {
    dispatch({ type: 'decrement' })
  }
  // ...
}

export default App

Redux-Toolkit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// store/counterSlice.js
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;
    },
  },
});

export const { increment, decrement } = counterSlice.actions;

export default counterSlice.reducer;

// store.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counterSlice";

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

// App.jsx
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { decrement, increment } from "./store/counterSlice";

export function Counter() {
  const count = useSelector((state) => state.counter.value);
  const dispatch = useDispatch();

  return (
    <div>
      <div>
        <button
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          Increment
        </button>
        <span>{count}</span>
        <button
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          Decrement
        </button>
      </div>
    </div>
  );
}
Dispatch
  • dispatch를 할 때마다 action type / payload를 작성해야 되던 것과 달리 slice에서 작성한 reducer을 바로 불러와서 사용이 가능하다.
1
2
3
4
5
// redux
dispatch({type: Actions.Add, payload: {value: ...} })

// RTK
dispatch(add(...))
Store
  • 기존 createStore가 아닌 configureStore를 사용한다.
  • redux-thunkdevtools를 기본으로 제공하며, reducer에서 반환된 새로운 상태를 Store 에서 관리한다.
  • createStore와 비슷하지만 {reducer: ...}로 작성해야 한다.
1
2
3
4
5
6
7
8
// redux
const store = createStore(reducer);

// RTK
const store = configureStore({
  reducer: reducer,
  middleWare:  (getDefaultMiddleware) => ...
})
Reducer
  • 기존의 상태관리와는 달리 mutating 으로 작성하는 것이 가능하다.
  • immer라이브러리를 사용하고 있기 때문에 실제로는 기존의 상태를 변형하는 것이 아니라, 기존 상태에 대한 변경을 감지하고 변경 상태를 바탕으로 새로운 immutable state를 생성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// redux
const reducer = (state, action) = {
  switch(action.type){
    case "increment" :
      return {...state, number: action.payload...}
  }
}

// RTK
const exampleReducerSlice = createReducer({
  name: "",
  initialState,
  reducers:{
    increment: (state, action) => {
      state.value = action.payload...
    }
  }
})
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.