728x90
CSR에서 세팅하는 거랑 뭐가 다른데?
Next.js는 서버 사이드에서 렌더링이 이루어집니다(SSR). 그래서 일반적인 CSR 환경에서 리덕스를 사용할 때와 달리 추가적인 작업이 필요합니다.
1. 서버 사이드에서 생성되는 리덕스 store와 이후 클라이언트 사이드에서 생성되는 리덕스 store는 다릅니다.
따라서 이 둘을 합쳐주는 로직이 필요합니다.
서버에서 생성한 store의 상태를 HYDRATE 라는 액션을 통해 client에 합쳐주는 리듀서를 작성해봅시다.
action.payload에는 서버에서 생성한 store의 상태가 담겨있어 이 둘을 합쳐 새로운 client 측 store의 상태를 만들게 됩니다.
// store/index.tsx
import {
combineReducers,
} from "@reduxjs/toolkit";
import { HYDRATE } from "next-redux-wrapper";
import axios from "axios";
import getConfig from "next/config";
axios.defaults.baseURL = getConfig().publicRuntimeConfig.apiServerUrl;
export const reducer = (state, action) => {
if (action.type === HYDRATE) {
return {
...state,
...action.payload,
};
}
return combineReducers({
/* */
})(state, action);
};
2. Next.js에서는 페이지를 요청할 때 마다 렌더링이 이루어집니다.
따라서 유저가 페이지를 요청할 때마다 새로운 리덕스 store를 생성할 수 있도록 makeStore 함수를 만들어줍시다.
// store/index.tsx
import {
combineReducers,
configureStore,
getDefaultMiddleware,
} from "@reduxjs/toolkit";
import { HYDRATE } from "next-redux-wrapper";
import axios from "axios";
import getConfig from "next/config";
axios.defaults.baseURL = getConfig().publicRuntimeConfig.apiServerUrl;
export const reducer = (state, action) => {
if (action.type === HYDRATE) {
return {
...state,
...action.payload,
};
}
return combineReducers({
/* */
})(state, action);
};
const makeStore = () =>
configureStore({
reducer,
middleware: [
...getDefaultMiddleware({ thunk: true, serializableCheck: false }),
],
});
3. 여전히 서버 사이드 메서드 내에서는 리덕스 store에 접근할 수 없습니다.
이를 위해 next-redux-wrapper 라이브러리를 사용할 수 있습니다.
// store/index.tsx
import {
AnyAction,
combineReducers,
configureStore,
getDefaultMiddleware,
} from "@reduxjs/toolkit";
import { HYDRATE, createWrapper } from "next-redux-wrapper";
import axios from "axios";
import getConfig from "next/config";
axios.defaults.baseURL = getConfig().publicRuntimeConfig.apiServerUrl;
export const reducer = (state, action) => {
if (action.type === HYDRATE) {
return {
...state,
...action.payload,
};
}
return combineReducers({
/* */
})(state, action);
};
const makeStore = () =>
configureStore({
reducer,
middleware: [
...getDefaultMiddleware({ thunk: true, serializableCheck: false }),
],
});
export const wrapper = createWrapper(makeStore, {
debug: process.env.NODE_ENV !== "production",
});
그리고 나서 _app 에서 withRedux HOC로 컴포넌트를 감싸주면 됩니다. 그럼 이제 각 페이지의 SSR 메서드(getInitialProps, getServerSideProps, getStaticProps)내에서 리덕스 store에 접근할 수 있게 됩니다.
// _app.tsx
import Head from "next/head";
import { wrapper } from "store";
import "index.css";
function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>BOOKBOOK</title>
</Head>
<Component {...pageProps} />
</>
);
}
export default wrapper.withRedux(MyApp);
728x90