커스터마이징

function useMutationQuery(queryKeys, api, options = {}) {
  const queryClient = useQueryClient()

  return useMutation(api, {
    onSuccess: () => {
      console.log('Success')
      queryClient.invalidateQueries(queryKeys)
      options.onSuccess && options.onSuccess()
    },
    onError: (error) => {
      console.log('ERROR')
      console.error(error)
      options.onError && options.onError(error)
    },
    onSettled: options.onSettled,
  })
}

export default useMutationQuery
----------------------------------------------------------------------------

import { useQuery } from '@tanstack/react-query'
// import axios from 'axios'
// import { getDestination } from '../api/myPage'

export default function useReactQuery(obj, key, api) {
  const { isLoading, isError, data, isSuccess } = useQuery([key, obj], () => api(obj))

  return { isLoading, isError, data, isSuccess }
}

// staleTime: 1000 * 60 * 5, // 데이터가 5분 동안 신선하다고 간주
// refetchInterval: 1000 * 60, // 1분마다 데이터를 다시 가져옴

데이터, key , api함수 인자 넘기는 훅스

React-Query 활용법

React Query는 비동기 데이터를 가져오고, 캐시하고, 동기화하며, 업데이트하고, 관리하는 작업을 수행, 이 라이브러리를 사용하면 컴포넌트가 서버 상태와 더 자연스럽게 상호 작용할 수 있으며, 캐싱, 동기화, 백그라운드 업데이트 등의 기능이 편리하게 제공(Component의 Lifecycle 구애 x)

서버의 상태를 불러오고, 캐싱하며, 지속적으로 동기화하고 업데이트 하는 작업을 도와주는 라이브러리

리액트쿼리를 활용한 다양한 전략과 몇가지 패턴들을 알아보겠습니다.

패턴들을 활용하여 더 나은 데이터 관리와 성능 향상을 추구할 수 있습니다.

**Query Caching**

“리액트 쿼리는 GC(가비지 컬렉터)로 캐쉬된 데이터를 관리하기 때문에 유용한 성능을 가집니다”

  1. Query Keys 설정: Query keys를 구조적으로 설정하여 여러 쿼리의 데이터를 쉽게 관리하세요.

    
    useQuery(['user', userID], fetchUserData);
    
  2. Dependent Queries: 하나의 쿼리가 다른 쿼리의 결과에 의존하도록 설정할 수 있습니다.

    
    const { data: userID } = useQuery('getUserID', fetchUserID);
    const { data: userData } = useQuery(['user', userID], fetchUserData, { enabled: !!userID });
    

    ⇒ userIdD가 존재할 때 실행되는 조건을 걸어주는 의존방식 (user 정보들을 필요할때 get가능)

    Data Manipulation

    1. Mutation과 Query Invalidation: useMutation 후에 캐시를 무효화하여 항상 최신 상태를 유지합니다.

      
      const mutation = useMutation(updateUser, {
        onSuccess: () => {
          queryClient.invalidateQueries('user');
        },
      });
      
    2. Optimistic Updates: 빠른 UI 반응성을 위해 미리 변경을 적용하고 나중에 동기화합니다.

      
      const mutation = useMutation(updateUser, {
        onMutate: (newData) => {
          queryClient.cancelQueries('user');
          const oldData = queryClient.getQueryData('user');
          queryClient.setQueryData('user', newData);
          return { oldData };
        },
        onError: (err, newData, context) => {
          queryClient.setQueryData('user', context.oldData);
        },
      });
      

      ⇒ 내부적으로 미리 data를 변경하도록하여 디테일한 상황들을 제어할 수 있습니다. 여러 data가 겹치는 상황들을 모면할 수 있습니다.

      Performance Optimizations

      1. Pagination and Infinite Queries: 대용량 데이터셋을 효율적으로 처리합니다.

        
        useInfiniteQuery('todos', fetchTodos, {
          getNextPageParam: (lastPage, allPages) => lastPage.nextPage,
        });
        
      2. Prefetching: 미리 데이터를 가져와 뷰 전환이 빠르게 진행되도록 합니다.

        
        queryClient.prefetchQuery('user', fetchUserData);
        
      3. Stale Time and Cache Time 설정: 쿼리의 데이터가 얼마나 오래 유지되어야 하는지, 언제 새로 가져와야 하는지 설정합니다.

        
        useQuery('user', fetchUser, {
          staleTime: 1000 * 60 * 5,
          cacheTime: 1000 * 60 * 30,
        });
        

      ⇒ 페이지네이션, 무한스크롤, 성능향상, 데이터 리셋 설정 등 다양하게 활용가능합니다.

      Default Provider

      import { QueryClient, QueryClientProvider } from "react-query";
      
      // QueryClient 인스턴스 생성
      const queryClient = new QueryClient({
        defaultOptions: {
          queries: {
            staleTime: 1000 * 60 * 5, // 5 minutes
            refetchOnWindowFocus: false,
            retry: 1,
          },
          mutations: {
            onError: (error, variables, context) => {
              // Handle error
            },
            onSettled: (data, error, variables, context) => {
              // Code to run after success or error
            },
          },
        },
      });
      staleTime: 데이터가 새로운 것으로 간주되는 시간을 설정합니다.
      refetchOnWindowFocus: 윈도우 포커스가 변경될 때 자동으로 데이터를 다시 가져올지 여부를 설정합니다.
      retry: 쿼리가 실패했을 경우 재시도할 횟수를 설정합니다.
      onError, onSettled: 뮤테이션의 에러 핸들링과 성공/실패 후 실행될 코드를 설정합니다.
      이런 식으로 QueryClient의 기본 설정을 커스터마이징하면, 앱 전체에서 이러한 설정을 공유할 수 있습니다. 이렇게 함으로써 각각의 쿼리와 뮤테이션에서 매번 같은 설정을 반복하지 않아도 되므로 코드의 중복을 줄이고 유지보수성을 향상시킬 수 있습니다.
      
      function App() {
        return (
          <QueryClientProvider client={queryClient}>
            {/* 하위 컴포넌트 */}
          </QueryClientProvider>
        );
      }

    • staleTime: 데이터가 새로운 것으로 간주되는 시간을 설정합니다.
    • refetchOnWindowFocus: 윈도우 포커스가 변경될 때 자동으로 데이터를 다시 가져올지 여부를 설정합니다.
    • retry: 쿼리가 실패했을 경우 재시도할 횟수를 설정합니다.
    • onError, onSettled: 뮤테이션의 에러 핸들링과 성공/실패 후 실행될 코드를 설정합니다.

    “많은 컴포넌트에서 사용하는 useEffect로 인한 sideEffect를 줄이며 옵션만 부여하면 비교적 간단한 구조로 성능 뿐만이 아니라 유지보수가 용이하다”

    그럼에도 고려해야할 점들

    1. 학습 곡선: React Query는 많은 고급 기능과 설정 옵션을 가지고 있습니다. 이것은 상대적으로 높은 학습 곡선을 만들 수 있으며, 특히 작은 프로젝트나 간단한 앱에서는 과도하게 느껴질 수 있습니다.
    2. 추상화 수준: React Query는 비동기 데이터 처리의 많은 부분을 추상화합니다. 이것이 다수의 경우에는 도움이 되지만, 특별한 요구 사항이나 커스터마이징이 필요한 경우에는 제약이 될 수 있습니다.
    3. 번들 크기: 라이브러리 자체가 상당히 크며, 모든 기능을 활용하지 않는다면 프로젝트의 번들 크기를 불필요하게 증가시킬 수 있습니다.
    4. 서버 사이드 렌더링(SSR)과의 호환성: React Query는 서버 사이드 렌더링과 잘 작동하지만, 초기 설정이 다소 복잡할 수 있습니다. Next.js와 같은 프레임워크를 사용할 때 이 부분이 더욱 도드라질 수 있습니다.
    5. 커뮤니티 및 에코시스템: React Query는 상대적으로 새로운 라이브러리라서 아직 완전히 성숙한 커뮤니티와 에코시스템을 가지고 있지 않을 수 있습니다. 이는 문서가 부족하거나, 특정 문제에 대한 해결 방법을 찾기 어렵게 만들 수 있습니다.

    실제로 ag-grid 테이블이나 다양한 라이브러리로 다양한 내부 로직에서 리액트쿼리를 사용할 때, 그 라이브러리에 데이터가 적용이 안되는 문제점들을 경험./

    https://github.com/ssi02014/react-query-tutorial

    :자주 쓰이고 다양한 예시들이 들어있는 깃헙주소입니다.

0개의 댓글