front-end/Nextjs

[NextJs] React-Query로 ServrSide Rendering 구현하기

hojung 2022. 7. 30.
728x90
반응형

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를 통해 넘어온 데이터를 이용해 컴포넌트를 구성해주면 완성이다!

 

 

728x90
반응형

댓글