[Next.js] - Redux

NoowaH·2022년 1월 25일
0

Next.js

목록 보기
7/17
post-thumbnail
post-custom-banner

Next.js - Redux 설정


library :

yarn add redux react-redux next-redux-wrapper
yarn add @types/react-redux -D
  • react-redux : 일반 리액트 앱에서 사용되는 라이브러리

  • next-redux-wrapper : next.js 프로젝트에 필요한 wrapper api

  • @types/react-redux -D : 리덕스 전용 타입스크립트 타입



`store/index.ts` :
// "__NEXT_REDUX_WRAPPER_HYDRATE__" 리듀서를 추가
const reducer = (state, action) => {
  if (action.type === HYDRATE) {
    const nextState = {
      ...state, // use previous state
      ...action.payload, // apply delta from hydration
    };
    if (state.count) nextState.count = state.count;
    return nextState;
  }
  return rootReducer(state, action);
};

Screen Shot 2022-01-25 at 7 59 33 PM
  • chrome Redux DevTool 화면을 보면 리덕스 스토어 생성 (@@INIT) 이후 __NEXT_REDUX_WRAPPER_HYDRATE__ 인 리듀서를 추가하게 되는걸 볼 수 있다.

  • HYDRATE : 서버에서 처음 생성된 리덕스 스토어를 클라이언트에서 사용할 수 있도록 주입하는 역할

  • action.type === HYDRATE : 처음 생성된 후 상태를 주입할 때 실행되는 함수

  • hydration 이 끝나고 나면 직접 설정한 rootReducer를 반환한다



// middleware
const bindMiddleware = (middleware: any) => {
  if (process.env.NODE_ENV != "production") {
    const { composeWithDevTools } = require("redux-devtools-extension");
    return composeWithDevTools(applyMiddleware(...middleware));
  }
  return applyMiddleware(...middleware);
};

const initStore = () => {
  return createStore(reducer, bindMiddleware([]));
};
  • process.env.NODE_ENV != "production" : redux 의 환경 상태에 따라 "redux-devtools-extension" 미들웨어를 적용할지 지정

  • yarn dev next.js의 디벨롭먼트 환굥은 "development"


// store type
export type RootState = ReturnType<typeof rootReducer>;
  • 스토어의 타입을 리듀서로부터 얻을 수 있음

  • useSelector((store: RootState) => {}) 과 같은 방식으로 사용됨



Redux-Wrapper


store/index.ts :


import { HYDRATE, createWrapper } from "next-redux-wrapper"

...

const initStore = () => {
  return createStore(reducer, bindMiddleware([]));
}

export const wrapper = createWrapper(initStore)
  • 기본 리덕스 스토어를 createWrapper 로 감싸준다

import type { AppProps } from "next/app";
import { wrapper } from "../store";

const app = ({ Component, pageProps }: AppProps) => {
  return (
    <>
      <GlobalStyle />
      <Component {...pageProps} />
    </>
  );
};

export default wrapper.withRedux(app);
  • react 앱에서는 커스텀 컴포넌트로 마크업을 감싸지만 next 프레임워크에서는 export 하는 컴포넌트를 wrapper.withRedux() 함수로 감싼다

pages/index.tsx :


...
// redux-wrapper 7.0 이후의 방식
export const getServerSideProps = wrapper.getServerSideProps(
  (store) => async () => {
    console.log(store);
    // store 파라미터 내장 함수
    // {
    //   dispatch: [Function: dispatch],
    //   subscribe: [Function: subscribe],
    //   getState: [Function: getState],
    //   replaceReducer: [Function: replaceReducer],
    //   '@@observable': [Function: observable]
    // }
    try {
      const { data } = await getTodosAPI();
      store.dispatch(todosSliceActions.setTodo(data));
      return { props: { todos: data } };
    } catch (e) {
      return { props: { todos: [] } };
    }
  }
);

// 구버전 방식
// export const getServerSideProps = wrapper.getServerSideProps(
//   async ({ store }) => {
//     console.log(store);
//     try {
//       const { data } = await getTodosAPI();
//       return { props: { todos: data } };
//     } catch (e) {
//       return { props: { todos: [] } };
//     }
//   }
// );
profile
조하운
post-custom-banner

0개의 댓글