🔥딱 8일간! 인프런x토스x허먼밀러 역대급 혜택

블로그

RTK 쿼리는 SSR을 하고 싶어!

서론요즘 RTK 쿼리와 함께 Nextjs에서 SSR을 적용하는데 꽤 시간을 들이고 있습니다. 물론 리액트 쿼리라는 걸출한 패키지가 존재합니다. 그런데 어쩌겠습니까, 저의 마음 속 한 켠에는 이미 RTK 쿼리에 대한 열망이 불타올랐던 겁니다!... 사실은 리덕스로 노는 와중에 찾아볼 게 있어서 문서에 들어갔다가 영업당한 것에 가깝습니다. 이 글을 작성할 동기를 제공한 리덕스 공식 문서에게 크나큰 박수를 보내주시면 감사하겠습니다.그래서 사용하는 김에 SSR까지 적용해보면 어떨까? 라는 생각을 했습니다. 그렇습니다, 여러분. 오늘 글의 주제입니다.RTK 쿼리는 외로워요SSR의 원리는 간단합니다. 클라이언트사이드에서 요청을 보내면 서버사이드에서 원래 클라이언트사이드에서 했어야 할 작업들을 대신 수행해 주는 겁니다. 그리고 그 결과가 적용된 말끔한 HTML을 응답해 줍니다.Nextjs는 이런 작업을 아주 멋지게 처리해 줄 getServerSideProps라는 함수를 제공합니다. 해야 하는 작업을 수행한 후 얻은 데이터를 페이지 컴포넌트의 props로 넣어 주는거죠.이 쯤에서 문제가 생깁니다. 우리는 props가 아닌 RTK 쿼리를 사용해야 하기 때문입니다. getServerSideProps 함수 안에서 RTK 쿼리를 디스패치하는 부분까지는 가능합니다. 그러나 클라이언트사이드의 RTK 쿼리는 서버사이드에서 무슨 일이 생겼는지 알지 못합니다. 서버사이드의 RTK 쿼리 혼자 외롭게 남아있게 되는 겁니다.그럼 어떻게 해야 할까요? 어떤 방식으로 서버사이드의 RTK 쿼리 스토어를 클라이언트사이드로 전달해 줄 수 있을까요?next-redux-wrappernext-redux-wrapper 패키지가 나설 차례입니다. 이 패키지는 서버사이드의 스토어를 클라이언트사이드 스토어에 덮어 씌워 줍니다. 서버사이드에서 실행된 RTK 쿼리를 클라이언트사이드로 가져오는 게 가능해진다는 의미이기도 합니다.store.tsnext-redux-wrapper를 적용하기 위해 약간의 수정이 필요합니다.// store.ts /** * configureStore를 감싸는 makeStore 함수를 작성 * @param context `next-redux-wrapper`에서 제공하는 context */ export const makeStore = (context: Context) => { return configureStore({ reducer: { something: somethingReducer, [rtkQueryApi.reducerPath]: rtkQueryApi.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat( rtkQueryApi.middleware, ), }); }; // makeStore 함수의 ReturnType를 가져와 타입 작성 type AppStore = ReturnType<typeof makeStore>; export type AppState = ReturnType<AppStore["getState"]>; export type AppDispatch = AppStore["dispatch"]; /** * `next-redux-wrapper`에서 제공하는 `createWrapper` 함수로 만들어진 wrapper를 export */ export const wrapper = createWrapper<AppStore>(makeStore, {debug: true}); // ^ // 작성된 makeStore 함수를 넘김다음과 같이 리덕스 스토어를 설정합니다. configureStore 함수로 만들어진 store를 바로 쓰는 대신 next-redux-wrapper 패키지에서 제공하는 createWrapper 함수로 wrapper를 만들어 사용합니다._app.tsx// _app.tsx function MyApp({ Component, pageProps }: AppProps) { return ( <Component {...pageProps} /> ); } // `store.ts`에서 생성된 wrapper로 MyApp 컴포넌트를 감쌈 export default wrapper.withRedux(MyApp)react-redux 패키지의 Provider 컴포넌트로 감싸던 기존의 방식 대신 wrapper.withRedux 함수로 MyApp 컴포넌트를 감쌉니다.좋습니다. next-redux-wrapper를 사용할 준비가 끝났습니다.SSR이제 RTK 쿼리를 서버사이드에서 사용해봅시다. 생각보다 정말 간단합니다.// store를 쓰기 위해 작성한 `wrapper`의 `getServerSideProps` 함수를 사용함 export const getServerSideProps = wrapper.getServerSideProps( (store) => async (context) => { // RTK 쿼리 디스패치 store.dispatch(rtkQueryApi.endpoints.getSomething.initiate({})); // 실행된 것이 끝날 때까지 대기 await Promise.all(cropApi.util.getRunningOperationPromises()); return { props: {}, }; } );다음과 같이 RTK 쿼리를 서버사이드에서 실행할 수 있습니다.하지만 문제가 생기게 됩니다. 클라이언트사이드의 스토어는 아무 것도 바뀌지 않았습니다. next-reudx-wrapper 패키지를 설정하는 과정에서 문제라도 생겼던 걸까요?RTK Query 설정이런, RTK Query의 api를 확인해 보니 한 가지 설정을 빠뜨렸습니다.export const rtkQueryApi = createApi({   ...   // 서버사이드에서 실행된 쿼리를 클라이언트에 hydrate   extractRehydrationInfo(action, { reducerPath }) {     if (action.type === HYDRATE) {       //                ^       //   next-redux-wrapper에서 제공          // 실행된 쿼리(reducerPath)를 리턴       return action.payload[reducerPath];     }   }   ... });HYDRATE 액션 때 서버사이드에서 실행된 쿼리를 전해주는 extractRehydrationInfo 함수를 설정해줘야 합니다.혹시 다 설정해줘야 하냐구요? 맞습니다. 서버사이드에서 실행될 예정인 쿼리와 뮤테이션을 다루는 createApi 함수는 모두 같은 설정을 해야 합니다. 안하면 쿼리와 뮤테이션들이 외로워 합니다.확인해봅시다이제 제대로 데이터가 전해졌는지 확인해봅시다.redux devtools에 들어가 액션을 살펴보세요. __NEXT_REDUX_WRAPPER_HYDRATE__ 안에 원하는 데이터가 들어 있다면 성공입니다.사용const ExampleComponent = () => { const { data } = useGetMyCropsQuery({}); return ( { data ? <div>{data.something}</div> : <div>...</div> } ) }기존과 같이 훅으로 사용합니다.TMI왜 Provider 컴포넌트를 사용하지 않나요?next-redux-wrapper가 Provider 컴포넌트의 역할을 합니다.도움이 됐나요?날씨가 추우니 손도 어는 기분이네요. 여러분들은 따뜻한 손으로 개발하고 있으시죠?그렇다고요? 좋습니다, 오늘도 즐거운 개발 되세요!References[createApi | Redux Toolkit # extractRehydrationInfo](https://redux-toolkit.js.org/rtk-query/api/createApi#extractrehydrationinfo)[Server Side Rendering | Redux Toolkit](https://redux-toolkit.js.org/rtk-query/usage/server-side-rendering)[GitHub - kirill-konshin/next-redux-wrapper: Redux wrapper for Next.js](https://github.com/kirill-konshin/next-redux-wrapper)  

프론트엔드SSRRTKQueryReduxReduxToolkitReduxToolkitQueryNextjs

바다소금

[ 발자국 ] 렌더링 방식, Cursor AI 경험 (25.05.26~25.06.01)

본 게시글은 Next.js 완벽 마스터 (v15): Notion 기반 개발자 블로그 만들기 (with Cursor AI)를 수강하면서 작성한 내용입니다. 학습 내용여러 가지 렌더링 방식(CSR, SSR, SSG, ISR, SPA)의 차이점에 대해 학습하였다.여러 가지 렌더링 방식에 대해 확실하게 알아가는 과정을 거칠 수 있어서 좋았다.웹페이지의 목적에 따라서 적합한 렌더링 방식을 적용해야겠다고 생각했다.[ 보완하고 싶은 점 ]실제 프로젝트를 통해 각 렌더링 방식 직접 구현해보기하이브리드 렌더링 전략에 대한 추가 학습하기Cursor AI를 이용하는 기본적인 방법에 대해 실습하는 시간을 가졌다.Cursor AI의 기본 사용법을 알아볼 수 있었다.Project Rule 설정을 통해 명확한 fit에 따른 AI 이용이 가능하다는 점을 알 수 있었다.[ 보완하고 싶은 점 ]복잡한 프로젝트에 대해 Cursor AI를 효율적으로 사용해보는 경험 쌓기Project Rule에 대해 세밀한 조정 경험해보기Cursor AI 고급 사용법 탐구하기Next.js 프로젝트 세팅법에 대해 학습하였다.Next.js의 기본 세팅법에 대해 알아볼 수 있었다.코드 작성을 도와주는 여러 가지 추가 패키지를 알아볼 수 있었다.[ 보완하고 싶은 점 ]고급 설정 옵션 학습해보기다양한 환경 설정 시나리오 경험 해보기  미션 과정[ 링크 ] 웹 렌더링의 다양한 방식 (CSR, SSR, SSG, ISR, SPA) 각 렌더링 방식의 기본 개념을 이해하는 것에 중점을 두고 미션을 수행하였다.CSR, SSR, SSG, ISR에 대한 기본적인 개념에 대해 더 구체적으로 탐색하는 시간을 가졌고, 각 렌더링 방식에 따라 가지는 장점과 한계점을 통해 어떤 목적의 사용 예시가 있을 수 있을지 생각해보았다.다만, 여러 렌더링 방식에 대한 실제 구현 경험이 더 필요하다고 생각했다.[ 링크 ] 모스 부호 번역기 with Cursor AICursor AI를 이용하는 과정을 실습해 보고자 모스 부호 번역기 웹페이지를 간단하게 만들어 보았고, 그 과정을 글로 작성해보았다.Cursor AI를 더 잘 이용할 수 있는 방법에 대한 연구가 필요하다는 생각을 했고, 더 복잡한 프로젝트에서 AI를 이용하는 경험을 해보면 좋겠다고 생각했다.[ 링크 ] Next.js 프로젝트 세팅해보기실전 사용을 위해서 구체적인 설명은 생략하고 Next.js 프로젝트를 세팅하는 과정을 간단하게 정리해보았다. 다양한 설정 옵션에 대한 이해가 부족하기 때문에 그에 대해서 더 다양하게 알아보는 시간이 필요하다고 생각했다. 

프론트엔드CursorAICSRSSRSSGISRNext.js렌더링프로젝트세팅

채널톡 아이콘