1. 무엇을 하려하는가?
NextJS가 강력한 이유 중 하나는 SSR(server-side-Rendering)을 제공하기 때문이다. 서버 단에서 미리 데이터를 포함한 html파일을 렌더링한 후 프론트 쪽으로 보내주기 때문에 한 번 사이트가 로딩 된 후에는 거의 로딩시간이 걸리지 않는다는 장점이 있고 검색엔진이 사이트들을 방문할 때 많은 데이터가 이미 렌더링 된 html에 포함되어 있으므로 검색 엔진 최적화에도 유리하다는 장점이 있다. 나는 이 ServerSide Rendering을 React-Query라이브러리를 사용하여 구현해보고자 한다.
2. 구현
1. _app.tsx
import Footer from "components/Layout/Footer";
import Header from "components/Layout/Header";
import "../styles/globals.css";
import { LayoutContainer } from "components/Layout/styled";
import type { AppProps } from "next/app";
import { useEffect, useState } from "react";
import { QueryClient, QueryClientProvider, Hydrate } from "react-query";
import { ReactQueryDevtools } from "react-query/devtools";
import "antd/dist/antd.css";
import wrapper from "store/configureStore";
import axios from "axios";
import { UserData } from "apis/Auth/types";
import { useDispatch } from "react-redux";
import { setUserData } from "store/slices/user-slice";
import { API_HOST } from "apis/api";
function MyApp({ Component, pageProps }: AppProps) {
//useState lazyinit을 사용해 QueryClient 인스턴스를 생성해
//QueryClientProvider의 client 값으로 전달해준다.
const [queryClient] = useState(() => new QueryClient());
const dispatch = useDispatch();
useEffect(() => {
axios.get(`${API_HOST}/user`, { withCredentials: true }).then((res) => {
if (res.data != null) {
const userData: UserData = {
email: res.data.email,
nickname: res.data.nickname,
userId: res.data.id,
userProfileImage: res.data.profileImage,
userDescription: res.data.profileDescription,
};
dispatch(setUserData(userData));
}
});
}, []);
return (
<>
<QueryClientProvider client={queryClient}>
<Hydrate state={pageProps?.dehydrateState}>
<LayoutContainer>
<Header />
<Component {...pageProps} />
<Footer />
</LayoutContainer>
</Hydrate>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</>
);
}
내가 구현한 _app.tsx인데 이 코드에서 react-query로 serverside Rendering을 구현할 때 필요한 것은
- queryClient를 생성해준 후 QueryClientProvider안에 넣어준다.
- <Hydrate> 태그에 pageProps.dehydratedState를 전달해준다.
- 만약 devTools를 연결하고 싶다면 ReactQueryDevtools를 연결한다.
2. NextJs의 Dynamic Routing Page [id].tsx
나는 NextJS의 Dynamic Routing을 이용하여 각 블로그 포스팅들의 detail page를 설계하려고 한다. 이 때 고려해야할 사항은 두 가지이다.
첫 번째는 query 변수로 오는 IPrams이다. 전체적인 틀은 같지만 블로그 포스터마다 데이터가 다르므로 같은 틀 안에 다른 데이터를 보여주는 기술인 dynamic routing은 query변수에 따라 다른 데이터들을 불러온다. 따라서 이 query변수를 신경써줘야한다.
두 번째는 각 디테일 페이지마다 넘어오는 실제 데이터들이다. 이 데이터들을 server side rendering으로 어떻게 구현할 지를 고민해봐야한다.
import MultiAlbumDetail from "components/multiAlbumDetail";
import useGetMultiAlbumDetail, { getMultiAlbumDetail } from "hooks/useMultiAlbumDetail";
import { GetServerSideProps } from "next";
import { useRouter } from "next/router";
import { ParsedUrlQuery } from "querystring";
import { dehydrate, QueryClient } from "react-query";
interface IParams extends ParsedUrlQuery {
id: string;
}
export const getServerSideProps: GetServerSideProps = async (context) => {
const { id } = context.params as IParams;
const queryClient = new QueryClient();
await queryClient.prefetchQuery(["multiAlbumDetail", id], () => getMultiAlbumDetail(id));
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
};
const MultiAlbumDetailPage = () => {
const router = useRouter();
const { id } = router.query;
const { data, isLoading } = useGetMultiAlbumDetail(id ? id : 16);
console.log("detail", data);
return (
<>
{isLoading || !data ? (
<div>is Loading...</div>
) : (
<>
<MultiAlbumDetail
Images={data?.data.multiAlbumDetail.Images}
title={data?.data.multiAlbumDetail.title}
content={data?.data.multiAlbumDetail.content}
createdAt={data?.data.multiAlbumDetail.createdAt}
User={data?.data.multiAlbumDetail.User}
/>
</>
)}
</>
);
};
export default MultiAlbumDetailPage;
나는 디테일 페이지를 다음과 같이 구성했는데 이 때 필요한 것은 NextJS의 getServerSideProps이다.
이 getServerSideProps안에 queryClient를 새로 생성해주고 불러올 데이터들을 요청하는 query문을 queryClient의 prefetchQuery안에 작성해준다. serverside Rendering을 구현하는 방법에는 다음과 같이 prefetchQuery문과 dehydratedState를 전달하는 방법 1개와 initialStateProps를 전달하는 방법 2가지가 있는데 이는 react-query공식 문서를 살펴보면 잘 나와있다. 나는 그 중 1번째 방법을 선택했다.
또한 getServerSideProps안에 미리 fetch할 query문을 작성해준 후 props안에 dehydratedState에 dehydrate를 이용해 아까 생성한 queryClient를 전달해준 후
컴포넌트 안에서 다시 데이터를 불러줄 훅을 부르게 되면 된다. 저기 useGetMultiAlbumDetail이라는 훅은 결국 react-query안에서 getMutiAlbumDetail(id)를 불러주는 훅으로써 모양은 다음과 같다.
그 후 data를 통해 넘어온 데이터를 이용해 컴포넌트를 구성해주면 완성이다!
'front-end > Nextjs' 카테고리의 다른 글
[Next JS] React-Query로 UseInfinityQuery이용하여 무한 스크롤 구현하기 with express.js (1) | 2022.08.11 |
---|---|
[NextJS] React-Query useMutation()사용하기 (2) | 2022.08.01 |
[NextJS] 동적 라우팅 (with React-Query) (2) | 2022.07.06 |
[NextJS] NextJS에서의 proxy설정 (2) | 2022.07.01 |
[NextJS] NextJS에서 Styled-components사용할 때 오류 해결 (2) | 2022.06.30 |
댓글