Next.js + Redux toolkit + TypeScript

<div>elop·2022년 7월 30일
3
post-custom-banner

React에서 상태관리 할때 압도적으로 Redux가 쓰이는건 맞지만 그냥 제일 먼저 나와서 많이 쓰는게 아닌가 싶다. 관리할 상태가 많아질 수록 파일이 너무 커진다.

최근에 recoil이랑 zustand를 잠깐 봤는데 (신세계임 ㅋ) 조만간 많이들 탈리덕스 하지 않을까... 싶다.
어쨌든 next.js + redux toolkit + typescript 예시를 하나 작성해보려한다.

install

$ yarn add redux react-redux @types/react-redux @reduxjs/toolkit next-redux-wrapper

$ npm i redux react-redux @types/react-redux @reduxjs/toolkit next-redux-wrapper

CurCategorySlice.ts

//   store/CurCategorySlice.ts

import { createSlice, PayloadAction } from '@reduxjs/toolkit';


export interface CurCategoryState {
  name: string;
}

const initialState: CurCategoryState = {
  name: 'none',
};

const CurCategorySlice = createSlice({
  name: 'CurCategory',
  initialState,
  reducers: {
    changeCurCategory: (
      state: CurCategoryState,
      action: PayloadAction<string>
    ) => {
      state.name = action.payload;
    },
  },
});

export const { changeCurCategory } = CurCategorySlice.actions;
export default CurCategorySlice;

현재 카테고리를 string으로 가지고 있는 state다.

index.ts

//   store/index.ts

import {
  configureStore,
  combineReducers,
  AnyAction,
  CombinedState,
} from '@reduxjs/toolkit';
import { createWrapper, HYDRATE } from 'next-redux-wrapper';
import CurCategorySlice, { CurCategoryState } from './CurCategorySlice';
import { Reducer } from '@reduxjs/toolkit';


export interface RootState {
  category: CurCategoryState;
}

const RootReducer = (
  state: RootState,
  action: AnyAction
): CombinedState<RootState> => {
  if (action.type === HYDRATE) return { ...state, ...action.payload };
  const combinedReducer = combineReducers({
    category: CurCategorySlice.reducer,
  });
  return combinedReducer(state, action);
};

const makeStore = () =>
  configureStore({
    reducer: RootReducer as Reducer<CombinedState<RootState>, AnyAction>,
    devTools: process.env.NODE_ENV === 'development',
  });

export const wrapper = createWrapper(makeStore);

reducer들을 합치는 combineReducers를 하지않고 바로 configureStore에 넣을 수도 있지만, 서버와 클라이언트쪽의 상태를 맞춰주기 위한 HYDRATE을 위해 이렇게 해줬다.

_app.tsx

...
import { wrapper } from '../store/index';
...

function MyApp({ Component, pageProps }: AppProps) {
  ...
}
  
export default wrapper.withRedux(MyApp);

사용하려면 MyApp을 wrapper로 씌워줘야한다.

적용

import { RootState } from '../../store/index';
import { useDispatch, useSelector } from 'react-redux';
import { changeCurCategory } from '../../store/CurCategorySlice';
const CategoryButton = (props: propType) => {
 
  ...
  
  const dispatch = useDispatch();
  const curCategory = useSelector((state: RootState) => state.category);

  const onClick = () => {
    ...
    dispatch(changeCurCategory('none'));
    ...
  };
  
  ...

이런식으로 사용하면 된다.

profile
기록장
post-custom-banner

0개의 댓글