Mutations

김동현·2023년 2월 12일
0

React Query

목록 보기
4/5
post-thumbnail

Mutations

Mutations란 서버 데이터를 업데이트하도록 서버에 요청을 보내는 동작(쿼리)입니다. 즉, DB의 데이터를 추가, 수정, 삭제하는 동작인 PUT, DELETE, POST와 같은 동작을 수행합니다.

즉, useQuery 훅은 GET 요청을 보내기 위해 사용되고 POST, PUT, PATCH, DELETE와 같은 메서드는 useMutation 훅을 사용합니다.

Mutations를 위해 React Query는 useMutation 훅을 제공합니다.

  1. useMutation 훅의 반환값은 useQuery 훅의 반환값과 유사하지만 추가적으로 mutate 메서드를 갖고 있습니다. mutate 메서드를 호출하면 실질적으로 요청을 전송합니다.

  2. 데이터를 변경하는 요청만 보낼뿐 서버 데이터를 저장하지 않으므로 쿼리 키를 필요로 하지 않습니다.

  3. isLoading은 존재하지만 isFetching은 존재하지 않습니다. 데이터에 대한 변경만 하며 변경에 대한 쿼리를 캐싱을 하지 않기때문입니다.

  4. 기본적으로 요청에 대한 재시도를 하지 않지만 재시도에 대한 설정을 할 수 있습니다. useQuery 훅의 경우 기본적으로 요청이 실패한 경우 3번의 재시도를 수행합니다.

useMutation

import { useMutation } from '@tanstack/react-query'

const { mutate, isLoading, isSuccess, isError } = useMutation(
  (params) => { 
    // data 조작
  },
  {
    onSuccess: (data) => { 
      // data 처리
    },
    onError: (error) => {
      // error 처리
    },
    onSettled: (data, error) => {
      // data, error 처리
    }
  }
)

Parameters

  1. mutationFn: (variables: TVariables) => Promise<TData> : 비동기 작업을 수행하는 Promise를 반환하는 함수를 작성합니다. useQuery 훅에 전달되는 콜백함수와는 달리 mutate 메서드를 수동으로 호출해야 실행되며, mutate 호출시 전달한 인수를 전달받습니다.

  2. Options: Object : 추가적인 설정을 할 수 있는 객체를 전달할 수 있습니다. 작성할 수 있는 옵션은 아래와 같습니다.

    • onMutate: (variables: TVariables) => Promise<TContext | void> | TContext | void
      : 첫 번째 인수로 전달한 비동기 작업 이전에 실행되는 메서드이며, mutate 호출할 때 전달한 인수를 전달받습니다.

    • onSuccess: (data: TData, variables: TVariables, context?: TContext) => Promise<unknown> | void
      : mutation이 성공한 이후헤 호출되는 메서드이며, mutateAsync 메서를 실행한 경우 인수로 비동기 처리 결과, mutate 메서드 인수를 전달받습니다.

    • onError: (err: TError, variables: TVariables, context?: TContext) => Promise<unknown> | void
      : mutation이 실패한 경우 호출되는 메서드이며, 해당 메서드는 인수로 에러 객체, mutate 인수를 전달받습니다.

    • onSettled: (data: TData, error: TError, variables: TVariables, context?: TContext) => Promise<unknown> | void
      : mutation이 성공 혹은 실패한 이후에 호출되는 메서드입니다. 해당 메서드는 인수로 비동기 처리 결과, 에러 객체, mutate 메서드 인수를 전달받습니다.

Returns

useMutation 훅은 객체를 반환하며 객체에 대한 프로퍼티는 아래와 같습니다.

  1. mutate: (variables: TVariables, { onSuccess, onSettled, onError }) => void
    : mutate 메서드를 호출하면 useMutation 훅 첫 번째 인수로 전달한 콜백함수가 실행되며, 호출 시 전달한 인수가 첫 번째 콜백함수에게 전달됩니다.

    mutate 메서드 인수로 객체 타입만을 전달할 수 있으며 mutateFn이 전달받는 인수 또한 객체 타입입니다.

  2. mutateAsync: (variables: TVariables, { onSuccess, onSettled, onError }) => Promise<TData>
    : mutate 메서드와 동일하지만 차이점으로는 Promise 객체를 반환합니다.

  3. isLoading: boolean
    : mutation이 진행중인 경우 true 값을 갖습니다.

  4. isError: boolean
    : mutation이 실패한 경우 true 값을 갖습니다.

  5. isSuccess: boolean
    : mutation이 성공한 경우 true 값을 갖습니다.

invalidateQuery

queryClient가 제공하는 메서드 중 invalidateQuery 메서드는 특정 쿼리 데이터를 명시적으로 무효화해주는 역할을 합니다.

여기서 무효화란 쿼리의 staleTime을 0으로 만들어줌으로서 React Query가 re-fethcing하도록 만들어줍니다.

일반적으로 Mutations로 변경된 쿼리에 대해 쿼리의 staleTime을 0으로 만들어 주고, React Query가 이를 re-fetching 하도록 만들기 위해 사용합니다.

import { useQueryClient, useMutation } from '@tanstack/react-query'

const Component = () => {
  const queryClient = useQueryClient()
    
  const { mutate } = useMutation(
        (prarms) => {
          // ,,,
        },
        {
          onSuccess: () => {
            // 성공시 mutation된 쿼리 무효화 수행
            queryClient.invalidateQuery([queryKey,,,], {
              // exact: true 
            })
          }
        }
  )
}

export default Component

invalidateQuery 메서드의 인수로는 무효화할 쿼리 키를 전달합니다. 이떄 전달한 인수가 배열 형태의 쿼리 키라면 하나라도 일치하는 경우 해당 쿼리는 무효화됩니다.

만약 인수로 전달한 쿼리 키와 정확히 일치하는 쿼리만을 무효화하고자 한다면 두 번째 인수로 객체를 전달하고 객체에 exact 프로퍼티 값으로 true를 전달해주어야 합니다.

Optimistic Update

Optimistic Update란 서버에게 응답을 받기 전에 수동으로 쿼리 데이터를 업데이트하는 것으로 서버가 응답할 데이터를 미리 알고 있고, 통신이 성공한다는 보장을 전제하에 사용합니다. Optimistic Update를 사용하므로서 서버에게 응답을 받기 전에 미리 UI를 업데이트하여 UX측면을 개선할 수 있습니다.
만약 서버와 통신을 실패하는 경우 업데이트 이전 값으로 되돌려주어야 합니다(rollback).

Optimistic Update을 사용하기 위해서는 onMutate 옵션을 사용해야 하며, queryClient가 제공하는 cancelQueriessetQueryData를 이용해야 합니다.

import { useQueryClient, useMutation } from '@tanstack/react-query'

const Component = () => {
  const queryClient = useQueryClient()
    
  const { mutate } = useMutation(
        (params) => {
          // ,,
        },
        {
          onMutate: (params) => {
            // 수동적으로 쿼리 데이터를 갱신해주기 위해서 실행되는 쿼리를 취소해주어야 합니다
            // 취소해주지 않으면 수동적으로 갱신한 쿼리 데이터가 덮어씌워지게 됩니다
            queryClient.cancelQueries([queryKey,,,])
                
            // 수동으로 쿼리 데이터를 갱신시켜 줍니다
            queryClient.setQueryData([queryKey,,,], data)
                
            // 실패할 경우 이전 쿼리 데이터로 되돌려야 하므로 기존 쿼리 데이터를 반환해주어야 합니다
            const previousQueryData = queryClient.getQueryData([querykey,,,])
                
            // rollback을 시켜주기 위해 기존 쿼리 데이터를 반환해주어야 하며
            // 객체 타입으로 반환해주어야 합니다
            return { previousQueryData }
          },
          onSuccess: () => {
            // ,,,
          },
          // onError 메서드 세 번째 인수로 onMutate 메서드가 반환한 값을 전달받습니다
          onError: (error, params, context) => {
            // 통신에 실패한 경우 이전 쿼리 데이터로 쿼리 데이터를 다시 갱신시켜주어야 합니다
            queryClient.setQueryData([queryKey,,,], context.previousQueryData)
          }
        }
  )
}

export default Component             
profile
Frontend Dev

0개의 댓글