본문 바로가기
nextjs

next-redux-wrapper 이해하기

by spare8433 2023. 2. 2.

nextjs 에서 redux 를 사용하기 위해서는 next-redux-wrapper 가 필수적으로 필요한 이유가 궁금했다.

본문 일부 내용 번역

정적 앱용 Redux 를 설정하는 것은 다소 간단하다 모든 페이지에 제공되는 단일 Redux 저장소를 만들어지기 때문에.


Next.js static site generator or server side rendering 이 관련되면 Redux 연결 구성 요소를 렌더링하기 위해 서버에 다른 저장소 인스턴스가 필요하기 때문에 작업이 복잡해지기 시작합니다.


또한 초기 값 관련해서 reduxstore 에 접근해야 할 수 도 있다.


next-redux-wrapper 는 자동으로 스토어 인스턴스를 생성하고 모두 동일한 상태를 갖도록 합니다.

 

이해 과정


실제로 처음 nextjs 를 사용할때 예상과 달리 store 내용이 초기화 되고 오류를 만난 기억이 있다.


여기서부터 내가 이해한 부분 오류에 주의


nextjsSSR 를 구현한다고 봤을 때 React 처럼 CSR 과 달리 웹서버에서 새로 페이지를(html 뿐만 아니라 데이터 리소스까지) 구성해 전달해준다.


이 말은 즉 redux 의 store 내용을 공유받지 못하면 화면을 구성하는데 문제가 생길 수 있다.

 

SSR 인 상황에서 문제없이 처리하려면 store 의 내용을 공유하여 웹서버입장에서 기존 redux 데이터와 이후 변경되는 데이터들을이 합쳐진 redux 상태를 참고하여 화면을 구성해야한다.


이 과정을 자연스럽게 해주는 라이브러리가 next-redux-wrapper 이다.

위 과정을 자세히 간단하게 설명하면 클라이언트의 redux store 에 서버에서 처리한 store 내용(예 : server side rendering 에서 dispatch 한 내용) 을 받아 Hydration 이 된다. (store 가 합쳐져 생성된다)

 

적용

redux-toolkit 적용한 예제이며 redux-toolkit 에서 import 한 configureStore() 부분은 무시해도 된다 createStore() 같은 store 생성 부분만 들어가면 된다. + ts 도 적용됨 타입은 참고만

 

store.ts

``next-redux-wrapper는 유저가 페이지를 요청할때마다reduxstore`를 생성하기 때문에 makeStore함수를 정의해서 넘기는것이다.

본문 중 : createWrapper함수는 첫 makeStore번째 인수로 받아들입니다. 이 함수는 호출될 때마다 makeStore새로운 Redux 인스턴스를 반환해야 합니다 .

// store.ts
const  makeStore  = () =>  configureStore({
    reducer: rootReducer as Reducer<ReducerStates, AnyAction>,
    ...
})
export type AppStore = ReturnType<typeof makeStore>; // `store` type
export const wrapper = createWrapper<AppStore>(makeStore);

 

rootReducer.ts

위에 설명한 Hydration 과정을 구현한 부분
action typenext-redux-wrapper 에서 import 해온 HYDRATE 를 설정하고 그 외 리듀서 내용도 추가한다.

// rootReducer.ts
import { HYDRATE } from  'next-redux-wrapper';
...

const rootReducer:RootReducerType = (state, action) => {
  switch (action.type) {
    case HYDRATE:
      return action.payload
    default: {
      const combinedReducer = combineReducers({
        ...
      })
      return combinedReducer(state, action)
    }
  }
};

 

pages/_app.ts

최상위 컴포넌트에 Provider 로 감싸서 마무리 최종으로 적용 시킨다.

// pages/_app.ts
import { Provider } from 'react-redux';
import { AppProps } from 'next/app';
import { wrapper } from '@store/store';
...

export default function MyApp({ Component, ...rest }: AppProps) {
  const { store, props } = wrapper.useWrappedStore(rest);
  return (
    <Provider store={store}>
      <Component {...props.pageProps} />
    </Provider>
  )
}

 

참고


https://simsimjae.medium.com/next-redux-wrapper%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0-5d0176209d14
https://helloinyong.tistory.com/315