최근에 흥미로운 블로그 글을 봤다.
https://tech.osci.kr/react-query/
React-Query 도입을 위한 고민 (feat. Recoil) - 오픈소스컨설팅 테크블로그 - 강동희
Web Frontend 개발을 할 때 React 를 사용하면서 마주하게 되는 여러 가지 문제점 중 하나는 state, 상태 관리에 관한 부분입니다. 프론트엔드 개발자라면 state 와 뗄 수 없는 인연을 맺고 있습니다.오늘
tech.osci.kr
Recoil을 사용중에 React-query에 도입에 대해 고민하는 글이었다. 나도 현재 프로젝트를 recoil을 사용하고 있어서 이 블로그 글에 대해 흥미를 느꼈고 글을 읽어 보았다.
여기서 말하는 사용이유는, "서버 데이터를 위한 로직이 과도하게 커지고, 그로 인해서 Redux를 활용하기 위한 보일러 플레이트가 비대해 진다는점" 이라고 한다.
사용 기술 스택
Nextjs : 14.0.4 (app router)
@tanstack/react-query : 5.13.4
주의 사항!!!
내가 초반에 많이 해맸던 이유는 버전확인을 하지않고 공식문서를 봤다는 것이다.
이걸로 인해 실수를 하는 다른 주니어들이 없기를 빌며 다음과 같이 기술스택을 적었다.
TanStack query 공식 홈페이지를 확인해보면
https://tanstack.com/
TanStack | High Quality Open-Source Software for Web Developers
High-quality open-source software for web developers. Headless, type-safe, & powerful utilities for State Management, Routing, Data Visualization, Charts, Tables, and more.
tanstack.com
다음과 같이 Framework와 version을 고를 수 가 있다. 여기서 version을 재대로 확인하지 않고 작업을 하면 문제가 발생할 수 있다.
나같은 경우, 이부분에서 문제가 발생을 했다. 나는 tanStack-query v5를 사용하면서 v4 문서를 보고 작업하다
Hydrate가 호출되지 않는 문제가 발생을 했었고, 한참 이유를 찾다가 다음과같이 Hydrate가 HydrationBoundary로 변경되었다는
이유를 알게되었다. 다음부터는 다음과 실수가 없을것이다...
공식문서에서 제공하는 방법
공식문서에서 nextjs를 사용하면서 app router를 사용할 때에 대해서 친절히 적어놓았다.
설치를 먼저 하자면,
나같은 경우는 2가지를 같이 설치를 했는데, 1번째는 react-query 설치, 2번째는 devtools설치이다. 2번쨰는 상태변화를 확인하기 좋기에 사용하면 좋을듯하다.
그리고 나서 SSR에 대해서 확인하고 싶으면, 사이드바 탭에서 Server Rendering & Hydration과 Advanced Server Rendering을
확인하면 된다.
공식문서에서 개념확인하기
서버 렌더링이란?
서버 렌더링은 페이지가 로드되자마자 사용자가 볼 수 있는 일부 콘텐츠를 갖도록 서버에서 초기 HTML을 생성하는 작업입니다.
이는 페이지가 요청될때(SSR) 요청시 발생시킬수 있습니다. 이전 요청이 캐시되었거나 빌드 시간(SSG)에 미리 발생할 수도 있습니다.
클라이언트 사이드 렌더링 (CSR)
클라이언트 사이드 렌더링 애플리케이션의 경우, 사용자 화면에 어떠한 콘텐츠가 표시되기 전에 최소한 3번의 과정이 있습니다.
서버 사이드 렌더링 애플리케이션에서는 1번과정이 완료되면 사용자는 내용을 볼 수 있고, 2번이 완료되면 페이지는 상호작용이 가능하고
클릭 가능한 상태가 된다고 한다.
서버에서 query를 prefetch하고, 그 cache를 dehydrate해서 클라이언트에 그것을 rehydrate하는 것
개념정리
dehydrate 와 hydrate
SSR에서 hydration의 개념을 먼저 살펴보자. 서버 사이드에서 먼저 정적인 페이지(HTML)을 렌더링하고, JS 코드가 모드 로드되면 이 HTML에 이벤트 핸들러 등을 붙여 동적인 페이지를 만드는 과정을 hydration이라 말한다. hydration을 직역하면 '수분 공급' 이라는 뜻인데, 즉 건조한 HTML에 수분(인터렉션, 이벤트 핸들러 등)을 공급하여 동적인 페이지를 만들어나가는 과정을 말한다. tanStack-react-query 에서도 hydration과 관련된 기능을 제공하고 있는데,
공식문서 중 hydration 페이지를 살펴보면 dehydrate 와 hydrate 메서드를 볼 수 있다. dehydrate는 나중에 hydrate로 공급할 수 있는 cache에 대한 고정된 표현을 생성하며, hydrate는 이전에 dehydrate된 state를 cache에 추가한다고 소개되어있다.
Nextjs App Router로 SSR 해보기
나는 nextjs App Router를 사용하고 있었기에 Advanced Server Rendering으로 확인을 했다.
우리가 해야될 첫번째 설정은 Provider 설정이다.
src/app/utils/providers.tsx
"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useState } from "react";
const Providers = ({ children }: { children: React.ReactNode }) => {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
},
},
})
);
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
};
export default Providers;
src/app/layout.tsx
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import Providers from "./utils/providers";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>
<Providers>{children}</Providers>
</body>
</html>
);
}
app router를 사용할 때는 getStaticProps같은 것을 사용하지 않고, 해당 페이지에서 바로 호출을 통해서 가능하다.
나는 home에서 Posts 컴포넌트로 데이터를 전달할 예정이다.
src/app/page.tsx
import {
HydrationBoundary,
QueryClient,
dehydrate,
} from "@tanstack/react-query";
import getPosts from "./posts/getPosts";
import Posts from "./posts/page";
export default async function Home() {
const queryClient = new QueryClient();
await queryClient.prefetchQuery({
queryKey: ["posts"],
queryFn: getPosts,
});
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<Posts />
</HydrationBoundary>
);
}
Posts 컴포넌트는 2가지 동작을 보여줄건데, prefetching으로 얻은 데이터가 렌더링 되는 과정과 client side rendering 했을때 데이터를 보여주는 방식 2가지를 비교해서 보여줄 것이다.
src/app/components/posts/Posts.tsx
'use client';
import { useQuery } from '@tanstack/react-query';
import React from 'react';
import getPosts from './getPosts';
const Posts = () => {
const { data, error } = useQuery({ queryKey: ['posts'], queryFn: getPosts });
const clientValue = useQuery({ queryKey: ['poosts'], queryFn: getPosts });
return (
<div className="flex flex-row">
<div>
{data?.map(({ title, id }) => {
return <div key={id}>{title}</div>;
})}
</div>
<div>
{clientValue.data?.map(({ title, id }) => {
return <div key={id}>{title}</div>;
})}
</div>
</div>
);
};
export default Posts;
type PostType = {
userId: number;
id: number;
title: string;
body: string;
};
const getPosts = async () => {
const res: PostType[] = await fetch('https://jsonplaceholder.typicode.com/posts').then(
(res) => res.json()
);
return res;
};
export default getPosts;
시연영상
마치면서
React-query를 이용해서 서버 사이드 렌더링을 사용해봤다. 근데 아직 react-query의 장점을 많이 못살린느낌이다. 내가 여기서 경험한것은 그냥 데이터 캐싱처리 뿐이지 나중에 실제 프로젝트에서 사용한다고 보면 에러처리, 로딩처리를 편하게 할 수 있다는 장점도 느껴볼 수 있을거 같다.
'NextJS' 카테고리의 다른 글
Nextjs/Typescript Card Slice 구현하기 (Giftwave) (0) | 2023.07.27 |
---|---|
GiftWave 프로젝트/휴대폰인증 (setInterval, useInterval) (0) | 2023.07.22 |
Molecule 과 Organism (by PhoneAuth) (0) | 2023.07.19 |
Nextjs 카카오 소셜 로그인(REST API 방식) (0) | 2023.07.08 |
Environment Variables (.env 공식문서 번역하기) (0) | 2023.07.03 |