RECORD

[redux-toolkit] 리덕스 툴킷 + 타입스크립트 상태 관리 / 리액트, RTK, Typescript

ez1n 2023. 5. 31. 13:21

 

[redux-toolkit]

 


 

리액트로 진행한 프로젝트에서 리덕스를 공부한 적이 있는데

리덕스의 보일러 플레이트 코드를 간소화하기 위해 리덕스 툴킷 (redux-toolkit, rtk)를 사용한 적이 있다.

 

공부하면서 노션에 정리해놓은 것을 다시 복기할 겸 정리하려고 한다.

 


 

 

<STUDY>

 

  • 상태 관리 라이브러리 (state management library) → redux, modox, recoil 등
  • state가 상위 component로 올라갈수록 관리하기 복잡해지는 현상 해결

 

Redux toolkit (RTK)

  • Redux 로직을 작성하고 저장소를 설정하는 프로세스(redux 작업)를 단순화
  • redux 저장소 구성의 복잡성, 많은 패키지 추가, 상용구 코드 해결 위해 사용하는 도구
  • API
    1. configureStore() : 단순화된 구성 옵션과 기본값을 제공(redux store설정)
    2. createSlice() : 초기 상태, 리듀서 함수의 객체, 슬라이스 이름을 받아 리듀서 및 상태에 해당하는 액션 생성자와 액션 유형을 자동으로 생성하는 함수 → redux 로직 작성 위한 표준 접근 방식

 

💡 설치

npm install @reduxjs/toolkit react-redux
or
yarn add @reduxjs/toolkit

 

💡 사용 방법

 

1. RootState, AppDispatch정의

type이기 때문에 store 파일에서 직접 export (따로 파일을 만들 필요 x)
// store.ts

import { configureStore } from '@reduxjs/toolkit';

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

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

 

2. useSelector, usedispatch를 hook으로 정의 → useAppSelector, useAppDispatch

  • type이 아닌 실제 변수(variable) 이므로 hooks.ts 같은 별도의 파일에 정의해야 한다.
  • type을 컴포넌트마다 임포트 하는 횟수를 줄여줌
// hooks.ts

import { useDispatch, useSelector } from "react-redux";
import type { TypedUseSelectorHook } from "react-redux";
import type { RootState, AppDispatch } from "./store";

export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

 

❗ useAppSelector를 따로 정의해야 하는 이유

- useSelector를 그대로 사용하는 경우 타입을 항상 명시해 주어야 하기 때문!

// useAppSelector 정의한 경우
import { useAppSelector } from '../app/hooks'
const count = useAppSelector(state => state.counter.count);

// useAppselector 정의하지 않은 경우
import { useSelector } from 'react-redux';
import { RootState } from '../modules';

const count = useSelector((state: RootState) => state.counter.count); // (state: RootState) 항상 써줘야함

 

3. store 추가

// index.tsx

import { Provider } from 'react-redux';
import { store } from './app/store';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

 

4. reducer 생성 및 추가

 

- Slice 정의

// countSlice.ts

import { createSlice } from "@reduxjs/toolkit";

interface menuState {
  value: number;
};

const InitialState: menuState = {
  value: 0,
};

export const CountSlice = createSlice({
  // state의 string name (보통 action type 상수로 사용함)
  name: 'count', 
  // 초기 state 값 (reducer가 undefined로 호출될 때마다 사용)
  initialState: InitialState, 
  // 특정 action type을 처리하기 위한 기능을 포함하는 객체
  reducers: {
    plus: (state) => {
      state.value++;
    },
    minus: (state) => {
      state.value--;
    },
  }
});

export const { plus, minus } = CountSlice.actions;
export default CountSlice.reducer;

 

- store에 reducer로 전달

// store.ts

import { configureStore } from '@reduxjs/toolkit';
import CountReducer from './reducer/countSlice';

export const store = configureStore({
  reducer: {
    count: CountReducer,
  }
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

 

💡 redux-toolkit을 사용하면 reducer에서 "mutating" 로직을 작성할 수 있다.

📌 redux-toolkit은 Immer 라이브러리를 사용하고 있어 실제로 상태를 변경하지 않는다. (불변성)

📌 Immer 라이브러리는 "draft state"의 변경 사항을 감지하고 이러한 변경 사항을 기반으로 새로운 불변 ​​상태를 생성하기 때문에 불변성을 유지할 수 있다.

 

 

5. 컴포넌트에서 사용하기

import {useAppDispatch, useAppSelector} from './app/store';
import {plus, minus} from './app/reducer/counterSlice';

export default Component1() {
  const dispatch = useAppDispatch(); // dispatch 임포트
  const count = useAppSelector(state => state.count.value); // count state 임포트
  
  return (
    <>
      <div>{count}</div>
      <div>
        <button type='button' onClick={() => dispatch(plus())}>
          plus
        </button>
        <button type='button' onClick={() => dispatch(minus())}>
          minus
        </button>
      </div>
    </>
  )
}

 

 


 

HNTECH 홈페이지 프로젝트를 하면서 상태관리도구(Redux)를 처음 사용해 보았다.

리덕스에 대한 자료를 찾아보면서 따로 설정해야 하는 부분도 많고 꽤 복잡하다는 생각이 들었는데

redux-toolkit을 통해 보일러플레이트를 확실히 줄일 수 있고 사용법도 간편해서 훨씬 편하게 느껴졌던 기억이 난다.

 

특히 redux-toolkit이 Immer 라이브러리를 사용하기 때문에 mutating 로직을 사용할 수 있다는 사실을 처음 알게되었다.

공부했던 내용을 다시 볼수록 새로운 내용을 알게 되는 것 같아서 즐거웠다 ㅎㅎ

 

공식 문서를 조금 더 자세히 읽어보면서 더 효율적으로 사용할 수 있는 방법도 고민해 봐야겠다!

 

 


 

<자세한 내용은 redux-toolkit 공식 홈페이지를 확인해 주세요>

 

 

Getting Started | Redux Toolkit

 

redux-toolkit.js.org