blog-thumbnail

GraphQL과 React Query로 서버 상태 관리하기

GraphQL
React Query
Hook
2024년 2월 2일

실무에서 React Query와 GraphQL을 같이 사용해야 했는데, 구글링 해보니 자료가 많이 없어서 제가 사용한 방법을 정리해보려고 합니다.

@apollo/clientuseQueryuseMutation의 인터페이스를 참고하였습니다.

useQuery #

import { RequestOptions, Variables, request } from 'graphql-request'

import {
  DefaultError,
  UndefinedInitialDataOptions,
  useQuery as useTanstackQuery,
} from '@tanstack/react-query'

export const useQuery = <
  T,
  V extends Variables = Variables,
  TError = DefaultError,
>({
  document,
  variables,
  ...rest
}: Pick<RequestOptions<V>, 'document' | 'variables'> &
  Omit<
    UndefinedInitialDataOptions<
      T,
      TError,
      T,
      [
        RequestOptions<V>['document'],
        RequestOptions<V>['variables'] | undefined,
      ]
    >,
    'queryKey' | 'queryFn'
  >) => {
  // queryKey는
  const queryKey: [
    RequestOptions<V>['document'],
    RequestOptions<V>['variables'] | undefined,
  ] = [document, variables]

  return useTanstackQuery({
    queryKey,
    queryFn: ({ queryKey }) =>
      // queryKey[0], queryKey[1]은 항상 document, variables인 것이 보장됨
      request<T>('https://example.com/graphql', queryKey[0], queryKey[1]),
    ...rest,
  })
}

documentvariables가 동일하다면 같은 쿼리라고 보고 queryKey를 구성하였습니다.

아래 코드를 보시면 @apollo/clientuseQuery를 사용할 떄와 비슷하게 사용할 수 있다는 것을 확인 할 수 있습니다.

// @apollo/client의 경우
const { loading, error, data } = useQuery<
  GetDogPhotoQuery,
  GetDogPhotoQueryVariables
>(GET_DOG_PHOTO, {
  variables: { breed },
  skip: true,
})

// 작성한 훅의 경우
const { isLoading, error, data } = useQuery<
  GetDogPhotoQuery,
  GetDogPhotoQueryVariables
>({
  document: GET_DOG_PHOTO,
  variables: { breed },
  enabled: false,
})

useMutation #

import {
  DefaultError,
  UseMutationOptions,
  useMutation as useTanstackMutation,
} from '@tanstack/react-query'
import request, { RequestOptions, Variables } from 'graphql-request'

export const useMutation = <
  T,
  V extends Variables = Variables,
  TError = DefaultError,
>({
  document,
  ...rest
}: Pick<RequestOptions<V>, 'document'> &
  Omit<UseMutationOptions<T, TError, V>, 'mutationKey' | 'mutationFn'>) => {
  const mutationKey: [RequestOptions<V>['document']] = [document]

  return useTanstackMutation({
    mutationKey,
    mutationFn: (variables) =>
      request<T>(
        'https://example.com/graphql',
        document,
        variables,
      ),
    ...rest,
  })
}

이렇게 하면 @apollo/clientuseMutation 훅 인터페이스와 비슷하게 사용할 수 있습니다.

// @apollo/client의 경우
const [addTodo, { data, loading, error }] = useMutation<
  AddTodoMutation,
  AddTodoMutationVariables
>(ADD_TODO)
addTodo({ variables: { type: input.value } })

// 작성한 훅의 경우
const {
  mutate: addTodo,
  isLoading,
  error,
  data,
} = useMutation<AddTodoMutation, AddTodoMutationVariables>({
  document: ADD_TODO,
})
addTodo({ type: input.value })

최근 게시물

김진근 • © 2024