인프런 커뮤니티 질문&답변

밍끼님의 프로필 이미지
밍끼

작성한 질문수

Next + React Query로 SNS 서비스 만들기

두개의 차이점

해결된 질문

작성

·

64

0

안녕하세요, 아래 ISR에 대해서 질문드렸었는데, nextjs 에서 2가지 구현 방법이있다고 해서
두가지가 어떤 차이점이 있고 어떻게 활용하는게 좋을지 궁금해서 질문드립니다!

1번 방법 = fetch API 의 revlidate를 활용하여 ISR 구현

import ProductList from "@/component/ProductList";
import { getQueryClient } from "@/component/TanstackQueryOption";

import { getProducts } from "@/fetch/getProducts";
import { dehydrate, HydrationBoundary, QueryClient } from "@tanstack/react-query";
import Image from "next/image"; 
  

export default async function ProductPage () {
  const queryClient = getQueryClient();

  await queryClient.prefetchQuery({
    queryKey:['products'],
    queryFn: getProducts,
  })

  return (
    <>
      <section className='visual-sec'>
      <Image src="/visual.png" alt="visual" width={1920}  height={300}/>
      </section>
      <section className="product-sec">
        <h2>상품 리스트</h2>
        <HydrationBoundary state={dehydrate(queryClient)}>
          <ProductList />
        </HydrationBoundary>
      </section>
  </>
  )
}
import {
  isServer,
  QueryClient,
  defaultShouldDehydrateQuery,
} from '@tanstack/react-query'

function makeQueryClient() {
  return new QueryClient({
    defaultOptions: {
      queries: {
        staleTime: 10 * 1000,
      },
      dehydrate: {
        shouldDehydrateQuery: (query) =>
          defaultShouldDehydrateQuery(query) ||
          query.state.status === 'pending',
      },
    },
  })
}

let browserQueryClient: QueryClient | undefined = undefined

export function getQueryClient() {
  if (isServer) {
    return makeQueryClient()
  } else {
    if (!browserQueryClient) browserQueryClient = makeQueryClient()
    return browserQueryClient
  }
}
'use client'


import { getQueryClient } from '@/component/TanstackQueryOption';
import {
  QueryClientProvider,
} from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { ReactNode } from 'react'


export default function TanstackQueryProvider({ children }: { children: ReactNode }) {

  const queryClient = getQueryClient()

  return (
    <QueryClientProvider client={queryClient}>
      {children}
      <ReactQueryDevtools
        initialIsOpen={true}
      />  
    </QueryClientProvider>
  )
}
export const getProducts = async () => {


  const res = await fetch(`http://localhost:9090/api/products`, {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
    next: {
      revalidate: 10,
    }
  });
 
  const data = await res.json();


  const currentTime = new Date().toLocaleTimeString('ko-KR', {
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    fractionalSecondDigits: 3,
    hour12: false, 
  });

  if (typeof window === "undefined") {
    console.log('fetch products', 'server', currentTime);
    console.table(data);
  } else {
    console.log('fetch products', 'client', currentTime);
    console.table(data);
  }



  if(!res.ok) {
    throw new Error("Failed to fetch products");
  }

  return data;
}


2번 방법 = export const revalidate 로 시간 설정 후 fetch로 받은 data 값을 바로 렌더링 시키기


import Product from "@/component/Product";
import styles from '@/component/ProductList.module.css';

import Image from "next/image"; 

export const revalidate = 10;


export default async function Product2Page() {
  const data = await fetch('/api/products');
  const products = await data.json();

  console.log(revalidate, 'Product2Page');


 
  return (
    <>
    <section className='visual-sec'>
      <Image src="/visual.png" alt="visual" width={1920}  height={300}/>
    </section>
    <section className="product-sec">
      <h2>상품 리스트</h2>
      <div className={styles.productList}>
      {products.map((product: any) => (
        <Product key={product.item_no} product={product} />
      ))}
      </div>
    </section>
    </>
  )
}

2개다 ISR로 구현되며, 1번 방법은 Data Cache 캐싱 매커니즘을 활용하고,
2번 방법은 Full Router Cache 캐싱 매커니즘을 활용한다의 차이점으로 생각이 드는데,
이 외에 다른 차이점과 실제 개발을 하면서 선호되는 방식이 따로 있을까요? 해당 페이지만 보았을때는 2번 방법으로 해도 어차피 주기적으로 다시 생성해서 최신 데이터를 반영하면 복잡하게 react-query를 사용하고, Hydration을 하면서 데이터를 동기화할 필요가 있나 싶어서 어떻게 사용해야할지 감이 안잡히네여

답변 1

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

2번 방법으로 하면 페이지는 10초마다 리밸리데이트하더라도 fetch의 데이터는 영구적으로 캐싱일 것 같습니다. 프로덕트 목록이 업데이트 되는 것이라면 1번 방식을 해야할 것 같네요.

밍끼님의 프로필 이미지
밍끼
질문자

2번 방법으로해도 fetch Data가 변경되고 10초 이후에는 새로고침할때 변경된 데이터로 그려져서요ㅠㅠ

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

다시 문서 읽어보니까 const revalidate는 default value가 Infinity인데 fetch revalidate는 기본값이 없네요. 그러면 지금 상황에서는 둘이 똑같은 게 맞습니다. 1번에서는 fetch revalidate가 const revalidate를 낮추고, 2번에서는 const revalidate 값을 fetch revalidate가 따라가네요.

참고로 개발모드에서는 페이지 캐시가 작동하지 않으니 테스트할 때 유의하셔야 합니다.

밍끼님의 프로필 이미지
밍끼
질문자

답변 감사합니다!

밍끼님의 프로필 이미지
밍끼

작성한 질문수

질문하기