far

[React-Query] 기본적인 것들 본문

React/React-Query

[React-Query] 기본적인 것들

Eater 2024. 11. 21. 22:28

1. Query-Key

  • Query-Key란?
    Query-Key는 쿼리를 고유하게 식별하기 위한 키로, 데이터를 캐싱하거나 새로고침할지, 캐시에서 데이터를 사용할지를 결정한다. 보통 배열 형태로, 리소스 이름과 파라미터를 포함하여 사용한다. 예를 들어, ['todos', userId]처럼 설정할 수 있다.
  • Next.js 서버사이드에서의 Query-Key 사용
    서버에서 Query-Key를 설정해 데이터를 미리 가져오고, React Query가 이를 캐싱해 활용할 수 있다.
// app/layout.tsx

import { ReactQueryProvider } from './_providers';

import './globals.css';

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html>
      <body>
        <ReactQueryProvider>
          <main>{children}</main>
        </ReactQueryProvider>
      </body>
    </html>
  );
}
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query';

export default async function page() {
  const queryClient = new QueryClient();
  await queryClient.prefetchQuery({ queryKey: ['key'] queryFn: getAPI });
  const dehydratedState = dehydrate(queryClient);

  const data = await getAPI({ queryKey: ['key'] });

  return (
    <HydrationBoundary state={dehydratedState}>
      <Component data={data} />
    </HydrationBoundary>
  );

page.tsx에서 HydrationBoundary를 감싸 사용할 수 있다.

2. Mutations에서 mutationKey 사용하기

  • Mutation-Key란?
    Mutation-Key는 Query-Key와 비슷하게, mutation의 유형을 구분할 때 사용한다. 여러 종류의 mutation을 추적하거나 디버깅할 때 유용하다.
'use client';

const { mutate } = useMutation({
  mutationKey: ['todos', 'add'],
  mutationFn: newTodo => axios.post('/api/todos', newTodo),
  onSuccess: () => {
    queryClient.invalidateQueries(['todos']);
  }
});

3. invalidateQueries를 사용한 쿼리 무효화

  • 왜 invalidateQueries가 필요한가?
    mutation이 성공하면, React Query의 invalidateQueries로 관련 쿼리를 무효화하여 최신 데이터를 자동으로 가져오게 할 수 있다. 예를 들어, 새로운 Todo를 추가한 후에 ['todos'] 쿼리를 무효화해 목록이 업데이트되도록 한다.
const queryClient = useQueryClient();
const { mutate } = useMutation({
  mutationFn: newTodo => axios.post('/api/todos', newTodo),
  onSuccess: () => {
    queryClient.invalidateQueries(['todos']);
  }
});

4. 무한 스크롤: useInfiniteQuery vs SuspenseInfiniteQuery

  • useInfiniteQuery
    자동 페이지네이션을 지원하여 사용자가 스크롤할 때 데이터를 연속으로 불러온다. getNextPageParam 함수를 통해 다음 페이지가 있는지 판단한다.
'use client';

const {
  data,
  fetchNextPage,
  hasNextPage,
  isFetchingNextPage,
} = useInfiniteQuery({
  queryKey: ['todos'],
  queryFn: ({ pageParam = 1 }) => fetchTodos(pageParam),
  getNextPageParam: (lastPage) => lastPage.nextCursor,
  initialPageParam: 1, // 1페이지부터 시작 (초기 값, v5부터 적용)
});
  • SuspenseInfiniteQuery
    Suspense를 활용하여 무한 스크롤을 감싸 UX적으로 더 좋다고 한다. React 18 이상에서 Suspense를 통해 로딩과 에러 상태를 처리한다. enabled는 사용 불가능하다
'use client';

const SuspenseInfiniteScroll = () => (
  <Suspense fallback={<LoadingSpinner />}>
    <InfiniteQueryComponent />
  </Suspense>
);

const {
  data,
  fetchNextPage,
  hasNextPage,
  isFetchingNextPage,
} = useSuspenseInfiniteQuery({
  queryKey: ['todos'],
  queryFn: ({ pageParam = 1 }) => fetchTodos(pageParam),
  getNextPageParam: (lastPage) => lastPage.nextCursor,
  initialPageParam: 1, // 1페이지부터 시작 (초기 값, v5부터 적용)
});

5. Optimistic Updates

  • Optimistic Updates
    UI를 서버 응답 전에 업데이트해 사용자로 하여금 반응이 빠르게 느껴지도록 한다.
const { mutate } = useMutation({
  mutationFn: updateTodo,
  onMutate: async newTodo => {
    await queryClient.cancelQueries(['todos']);
    const previousTodos = queryClient.getQueryData(['todos']);
    queryClient.setQueryData(['todos'], old => [...old, newTodo]);
    return { previousTodos };
  },
  onError: (err, newTodo, context) => {
    queryClient.setQueryData(['todos'], context.previousTodos);
  },
  onSettled: () => {
    queryClient.invalidateQueries(['todos']);
  }
});
  • Pre-Fetching Data
    서버사이드에서 queryClient.prefetchQuery를 사용해 데이터를 사전에 가져온다.
'use server';

const queryClient = getQueryClient();
await queryClient.prefetchQuery(['todos'], fetchTodos);
const dehydratedState = dehydrate(queryClient);

 

  • Query Caching 및 갱신 전략
    staleTime을 설정하여 자주 사용하는 데이터는 일정 시간 동안 새로고침 없이 사용하도록 최적화할 수 있다.
  • 오류 처리와 리트라이
    쿼리의 retry 옵션을 통해 특정 횟수만큼 자동으로 재시도하거나 에러를 사용자에게 알릴 수 있다.

 

  • ESLint
    @tanstack/eslint-plugin-query/recommended는 쿼리 키의 유효성 검사, 잘못된 staleTime 사용 방지 등을 자동으로 체크해준다.
// eslintrc.json
{
  "extends": ["plugin:@tanstack/eslint-plugin-query/recommended"]
}
Comments