[ 프로젝트 ] next-redux-wrapper를 사용하여 next/redux-toolkit 연결하기

김민석·2021년 7월 11일
2

WORKOUT!

목록 보기
15/18

꼬박 이틀이 걸렸다...
redux-toolkit을 이해하는 데에 하루가 걸렸고 이 둘을 연결하는 데에 하루가 걸렸다.
여기에 typescript가 같이 들어와버리니 아직 매끄럽게 이해하지는 못했다.
그래도 크롬 개발자 도구를 보니 연결이 된 것을 알 수 있었다.

참고:


Store.ts

import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
import { createWrapper } from 'next-redux-wrapper';

import rootReducer from '../reducers/index.reducer';

const makeStore = () =>
  configureStore({
    reducer: rootReducer,
    // middleware: getDefaultMiddleware => getDefaultMiddleware(),
    // devTools,
    // preloadedState,
    // enhancers:
  });

export type AppStore = ReturnType<typeof makeStore>;
export type AppState = ReturnType<AppStore['getState']>;
export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, AppState, unknown, Action>;

export default createWrapper(makeStore);

github 예시를 참고하여 작성하였다.

다만 redux-toolkit 문서를 읽어보면, createSlice보다 createReducer가 action-creator 분리 등의 이점이 더욱 있는 것 같았기에, 나는 createReducer를 사용하였다.

wrapper를 만들어 export 해주었다.


아래의 export type으로 시작하는 세줄은 현재로서는 잘 모르겠다.
우선 위의 두 개는 store type과 state type을 내보내는 것으로 보이고,
AppThunk는 toolkit에 redux-thunk가 내장되어 있기 때문에 그때 사용하는 것으로 보인다.


reducers/exercise.ts


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

import { ADD } from '../actions/exercise.actions';

interface StringState {
  value: string;
}

const initialState = { value: 'hi' } as StringState;

const exerciseReducer = createReducer(initialState, builder => {
  builder.addCase(ADD, (state, action) => {
    state.value = action.payload;
  });
});

export default exerciseReducer;

우선 state는 {value : 'hi'}를 기본으로 해서 만들어 보았다.
createReducer를 이용해서 앞으로 다른 행동들에 대응하도록 만들 예정이다.


actions/exercise.ts


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

export const ADD = createAction<string>('string/hi');
export const hi = createAction<string>('string/ho');

action들은 기본적으로 다른 디렉토리에서 만들 예정이다. 기본 redux에서는 const ADD_TODO = 'ADD_TODO' 같은 것을 계속 만들어가면서 reducer의 분기와 action 객체 생성에 넣어주었었는데, toolkit에서는 그럴 필요가 없어졌다.

여기서 만든 action creater들은 각 컴포넌트에서 dispatch와 함께 사용하면 된다.


reducers/index.ts

import { combineReducers, AnyAction } from '@reduxjs/toolkit';

import { HYDRATE } from 'next-redux-wrapper';
import { AppState } from '../store/store';
import exerciseReducer from './exercise.reducer';

const rootReducer = combineReducers({
  exerciseReducer,
});

export const reducer = (state: AppState, action: AnyAction) => {
  if (action.type === HYDRATE) {
    return {
      ...state,
      ...action.payload,
    };
  }
  return rootReducer(state, action);
};

export default rootReducer;

여기를 작성하는 데에 애를 좀 먹었다. (최대한 혼자 작성해보고 싶었다.)

HYDRATE를 연결해주는 부분에 있어서는 보통 redux에서 reducer를 만드는 문법을 적용하였다.

위의 깃허브 예시에는 createSlice를 만들고, 그 slice마다 extra-reducer에 hydrate에 대응하게 각각 코드를 작성한 것으로 되어있는데, 읽는 입장에서는 괜시리 코드양만 늘어나는 결과만 가져오는 것으로 보인다.

AppState는 store.ts에서 정의한 type을 가져왔다. 또한 AnyAction은

export interface AnyAction extends Action {
// Allows any extra properties to be defined in an action
[extraProps: string] : any
}

이런 모양의 type이다.
따라서 모든 모양의 action이 들어올 수 있다는 의미로 AnyAction 타입을 지정하였다.


_app.js

import React from 'react';
import type { AppProps } from 'next/app';

import wrapper from '../redux/store/store';

const App = ({ Component }: AppProps) => {
  return <Component />;
};

export default wrapper.withRedux(App);

마지막으로 store 파일에서 정의한 wrapper를 이용해서 _app.js를 감싸주었다.

1개의 댓글

comment-user-thumbnail
2022년 6월 6일

감사합니다

답글 달기