[redux] redux toolkit를 사용하면서..

mj·2021년 7월 20일
1

에어비앤비 클론코딩을 하면서 유저 정보를 리덕스 스토어에 저장하기 위해서 리덕스 설정을 알아보게 되었다.

모듈 다운로드

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

타입설정

user의 리덕스 state값을 다음과 같이 UserType과 isLogged를 갖는 타입을 선언한다.

type UserType = {
    id: number;
    email: string;
    firstName: string;
    lastName: string;
    birthday: string;
    profileImage: string;
};

export type UserState = UserType & { isLogged: boolean };

Redux Toolkit

createSlice, PayloadAction

createSlice는 리듀서 함수의 객체, 슬라이스 이름, 초기 상태 값을 받아들이고 해당 액션 생성자와 액션 유형으로 슬라이스 리듀서를 자동으로 생성한다.
PayloadAction은 액션의 payload 필드의 타입을 지정할 수 있게 해주는 제네릭이다.

import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { UserType, userState } from '../types/user';

const initialState: UserState = { ... };
const user = createSlice({
	name: "user",
  	initialState,
  	reducers: {
    	setLoggedUser(state, action: PayloadAction<UserType>){
          state = { ...action.payload, isLogged: true }; //상태의 불변을 지키기 위해 spread 연산자로 객체를 복사하고 isLogged의 상태만 바꿔준다. 
          return state;
        }
    }
});

export const userActions = { ...user.actions }; // 유저에 등록된 액션들을 내보내기 한다.

Redux Wrapper

next에서는 react처럼 리덕스 스토어가 단 하나만 존재하지 않는다. 하지만 next는 유저가 요청하면 여러 개의 스토어를 갖게 된다.

const initStore: MakeStore<any> = () => {
  //configureStore는  기존에 store를 생성하는 함수를 만들어 
  //createStore를 하고 미들웨어를 추가하는 귀찮은 작업들을 해결해준다.
  const store = configureStore({
    reducer,
    devTools: true,
  });
  //현재 상태 트리를 반환하는 getState를 initialRootState에 반환한다.
  initialRootState = store.getState();
  return store;
};
const wrapper = createWrapper(initStore);

next는 유저가 페이지를 요청할 때마다 스토어를 만들어야 하기 때문에 MakeStore 함수를 정의하여 wrapper에 넘긴다.
_app.tsx에 wrapper.withRedux(App)으로 App컴포넌트를 감싸면 각 페이지의 getInitialProps, getServerSideProps, getStaticProps등에서 리덕스 스토어에 접근이 가능해진다.

이때 next의 스토어와 클라이언트의 스토어가 다르기 때문에 둘을 HYDRATE이라는 액션으로 합친다.

import { HYDRATE } from 'next-redux-wrapper';
import { combineReducers } from '@reduxjs/toolkit';

//rootReducer
const rootReducer = combineReducers({
  user: user.reducer,
});

//스토어의 타입, ReturnType은 특정 함수의 반환 타입을 추출한다.
export type RootState = ReturnType<typeof rootReducer>;
let initialRootState: RootState;

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

0개의 댓글