NextJS에선 React-Query를 어떻게 사용하는게 맞을까?

pingu·2023년 6월 8일
42


NextJS + React-query?

SSR이 많은 인기를 끌면서 NextJS를 많이 사용하게 되었다. 그렇다면 NextJS와 React-query를 같이 사용한다면 어떨까?

  • React-query는 Next에서 pre-fetching이 가능하다. 이로인해 성능 향상에 도움을 준다.
    📌pre-fetching이란? 페이지가 렌더링되기 전에 미리 데이터를 가져오는 것을 말한다. ( 데이터 캐싱 작업도 pre-fetching에 포함된다 )
  • 데이터 요청 코드를 쉽게 관리가 가능하다.
  • 동적 데이터를 관리하는 비동기 로직을 쉽게 다룰 수 있다.

    NextJS + React-query 쓰세요 두번쓰세요

어떻게 사용하지?

NextJS에서 React-query를 사용하는 방식에는 두가지 방식이 있다.

  • 서버에서 데이터를 미리 가져와 클라이언트에 전달하는 방식인 initialData
  • 서버에서 캐시를 dehydrate 후 클라이언트에서 hydrate를 하는 방식인 Hydration

initialData

직관적인 방법으로 작업하는 부분에서 SSR이 비교적 적은 경우에 사용된다.
react-query 의 기본값으로 SSR의 데이터를 넣어주는 것으로 데이터를 사용하는 간단한 방법이다.

export async function getStaticProps() {
  const posts = await getPosts()
  return { props: { posts } }
}

function Posts(props) {
  const { data } = useQuery({
    queryKey: ['posts'],
    queryFn: getPosts,
    initialData: props.posts,
  })
}
export const getPosts = () => axios.get('https://api.test.com/posts');

NextJS의 getStaticProps 또는 getServerSideProps 두 방법 중 하나로 가져온 데이터를 useQuery initialData옵션에 전달한다.
getServerSideProps의 경우, 위와 같이 export 설정을 해두면 nextJS는 매 요청마다 여기서 요청한 데이터를 props로 넘겨주며 페이지를 새로 pre-render한다.
getStaticProps의 경우, 위와 같이 export 설정을 해두면 nextJS는 빌드 타임에 여기서 반환된 데이터를 props로 넘겨주며 페이지를 새로 pre-render한다.

initialData 방식은 기본적으로 prefetching 을 하지 않기에 데이터가 캐싱되지 않는다.

데이터가 캐시되지 않으므로 필요하면 다시 가져와야 한다. 이로 인해 로딩 시간이 느려지고 서버 요청이 증가한다.

Hydration

SSR이 중요하고 다양한 곳에서 사용되는 프로젝트의 경우 많이 사용되는 방법으로, 한번 설정해두면 간편하게 SSR을 사용할 수 있는 방법이다.
서버에서 여러 쿼리를 미리 가져온 다음 해당 쿼리를 queryClient 로 dehydrating 한다.

// _app.jsx
import {
  Hydrate,
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'

export default function MyApp({ Component, pageProps }) {
  const [queryClient] = React.useState(() => new QueryClient())

  return (
    <QueryClientProvider client={queryClient}>
      <Hydrate state={pageProps.dehydratedState}>
        <Component {...pageProps} />
      </Hydrate>
    </QueryClientProvider>
  )
}
// pages/posts.jsx
import { dehydrate, QueryClient, useQuery } from '@tanstack/react-query'

export async function getStaticProps() {
  const queryClient = new QueryClient()

  await queryClient.prefetchQuery(['posts'], getPosts)

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  }
}

function Posts() {
  const { data } = useQuery({ queryKey: ['posts'], queryFn: getPosts })
  const { data: otherData } = useQuery({
    queryKey: ['posts-2'],
    queryFn: getPosts,
  })
}

initialData 방식과는 다르게 app.tsx 에 별도로 설정이 필요하다.
QueryClientProvider로 <Component {...pageProps} />을 감싸줬던 부분 사이에 추가적으로

<Hydrate state={pageProps.dehydratedState}>

를 추가적으로 감싸준다.
이는, 서버에서 렌더링된 상태를 클라이언트로 전달하고, 클라이언트에서 다시 렌더링하도록 하기 위함이다.

이후 post.tsx에서 QueryClient를 import해서 가져오고 QueryClient의 prefetchQuery 메소드를 이용하여 'posts' 데이터를 캐싱한다.

그리고 마지막으로 dehydrate를 이용해 캐시 데이터를 지우고 dehydratedState props를 전달한다.

Hydration 방식은 기본적으로 prefetching 으로 데이터를 캐싱이 가능하다.
서버 데이터를 그대로 쓰는 것이 아닌 캐싱한 데이터를 불러오기 때문에 initialData 방식에 비해 데이터 조회가 느릴 수 있다.


어디에 적합할까?

NextJS에서는 getStaticProps 또는 getServerSideProps에서 props 객체를 페이지로 전달한 후에 리액트 쿼리의 initialData 옵션을 이용해서 SSR을 구현할 수 있다.

이렇게 하는 방식이 잘못된 것은 아니지만 권장하지 않는다.

이유는 깊이 있는 컴포넌트 단에서 서버 사이드 렌더링한 데이터가 필요할 경우 해당 컴포넌트까지 props로 전달을 해줘야하는 불편함이 있다. ( propsdriling이 발생할 수 있다. )

반면에 Hydration 방식은 서버 사이드 렌더링시 사용했던 query key(식별자)를 이용하면 데이터를 불러올 수 있다. 공식 문서에서도 InitialData 옵션으로 설정하는 방법보다는 Hydration 방식을 권장하고 있다.

정리 및 비교

정리

SSR에서 React Query를 사용하려면 initialData와 Hydration 중 하나를 선택해야 한다.

  • initialData은 서버에서만 데이터를 조회하기 때문에 클라이언트에서 데이터를 조회할 수 없다.
  • initialData은 클라이언트에서 데이터를 캐시할 수 없기 때문에 데이터를 조회할 때마다 서버에 요청해야 한다.
  • Hydration은 클라이언트에서 캐싱된 데이터를 조회하기 때문에 클라이언트에서 데이터를 조회할 수 있다.
  • Hydration은 클라이언트에서 데이터를 캐시할 수 있기 때문에 데이터를 조회할 때마다 서버에 요청할 필요가 없다.

비교

initialData는?

  • 데이터 요구 사항이 간단한 경우
  • 데이터가 자주 업데이트되지 않고 요청 시마다 다시 가져올 수 있는 경우
  • 캐싱의 우선 순위가 높지 않고 단순성과 사용 편의성에 중점을 둔 경우

SSR이 비교적 적은 경우에 사용된다.

Hydration는?

  • 복잡한 데이터 요구 사항이 있는 경우
  • 데이터가 자주 업데이트되고 캐싱이 우선 순위가 높은 경우
  • 성능이 중요하고 네트워크 요청을 줄이는 것이 중요한 경우

SSR이 비교적 많은 경우에 사용된다.

profile
코딩공부 리뷰

1개의 댓글

comment-user-thumbnail
2023년 6월 17일

Hello. I like to play blackjack and it is important for me to have a website that is optimised and easy to use. I've been using https://huntleywealth.com/ for over a year and I'm happy with it. The interface is user-friendly and comfortable. I like the way blackjack is played here, and I can also contact the dealer live, which makes the game more interesting.

답글 달기