SSR이 많은 인기를 끌면서 NextJS를 많이 사용하게 되었다. 그렇다면 NextJS와 React-query를 같이 사용한다면 어떨까?
NextJS에서 React-query를 사용하는 방식에는 두가지 방식이 있다.
직관적인 방법으로 작업하는 부분에서 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 을 하지 않기에 데이터가 캐싱되지 않는다.
데이터가 캐시되지 않으므로 필요하면 다시 가져와야 한다. 이로 인해 로딩 시간이 느려지고 서버 요청이 증가한다.
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는?
SSR이 비교적 적은 경우에 사용된다.
Hydration는?
SSR이 비교적 많은 경우에 사용된다.
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.