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

밍끼님의 프로필 이미지

작성한 질문수

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

두개의 차이점

해결된 질문

24.10.23 11:57 작성

·

22

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

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

2024. 10. 23. 14:03

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

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

2024. 10. 23. 14:16

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

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

2024. 10. 23. 14:33

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

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

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

2024. 10. 23. 15:26

답변 감사합니다!

밍끼님의 프로필 이미지

작성한 질문수

질문하기