Programming

[TIL] useMutation(react-query)

jay-dev 2023. 7. 31. 02:31

Install & Setting

v5 install 명령어

yarn add @tanstack/react-query@beta


devtools 설치 명령어

npm i @tanstack/react-query-devtools


tanstack/react-query v5는 현재 베타버전으로 사소한 변경이 있을지도 모름
v4 사용 권장

 

useMutation v3/v5  기본 사용법 비교

 

import { useMutation } from 'react-query';

function TodoAdder() {
  const mutation = useMutation(addTodo, {
    onSuccess: () => {
      console.log('Todo added!');
    },
    onError: (error) => {
      console.error('Failed to add todo', error);
    },
  });

  const handleAddTodo = () => {
    mutation.mutate({ text: 'New Todo' });
  };

  return (
    <div>
      <button onClick={handleAddTodo}>Add Todo</button>
      {mutation.isLoading && <span>Adding todo...</span>}
      {mutation.isError && <span>Error: {mutation.error.message}</span>}
      {mutation.isSuccess && <span>Todo added successfully!</span>}
    </div>
  );
}

V5

import { useMutation } from 'react-query';

function TodoAdder() {
  const { mutate, isLoading, isError, error, isSuccess } = useMutation(addTodo, {
    onSuccess: () => {
      console.log('Todo added!');
    },
    onError: (error) => {
      console.error('Failed to add todo', error);
    },
  });

  const handleAddTodo = () => {
    mutate({ text: 'New Todo' });
  };

  return (
    <div>
      <button onClick={handleAddTodo}>Add Todo</button>
      {isLoading && <span>Adding todo...</span>}
      {isError && <span>Error: {error.message}</span>}
      {isSuccess && <span>Todo added successfully!</span>}
    </div>
  );
}

V4,V5의 구조분해할당 방식이 useQuery 사용방식이랑 유사해 훨씬 직관적이고 사용하기 쉬움,

mutation.mutate , mutation.isLoading => mutate , isLoading 처럼 사용법이 간단하고 코드량이 줄어듦

 

invalidatedQueries

import { useMutation, useQueryClient } from 'react-query';
function SomeComponent() {
  const queryClient = useQueryClient();

  const mutation = useMutation(addTodo, {
    onSuccess: () => {
      // TODO가 추가된 후 TODO 목록 쿼리를 무효화하여 최신 상태로 가져옴
      queryClient.invalidateQueries('todos');
    },
  });

  const handleAddTodo = (newTodo) => {
    mutation.mutate(newTodo);
  };
}

invalidateQueries의 핵심:
무효화: 특정 쿼리의 캐시된 결과를 "무효"로 표시

데이터 변경 후 동기화: 예를 들어, 우리가 TODO 항목을 추가하는 동작을 수행한 후,
TODO 목록을 최신 상태로 유지하기 위해 invalidateQueries를 사용하여 TODO 목록 쿼리를 무효화할 수 있음

일관성 유지: 여러 사용자가 동시에 같은 데이터에 액세스하고 변경할 수 있는 시스템에서는
한 사용자의 변경이 다른 사용자의 보는 데이터에 영향을 미칠 수 있음
invalidateQueries를 사용하여 변경이 발생할 때마다 데이터를 최신 상태로 동기화하여 일관성을 유지

 

CancleQueries

const queryClient = useQueryClient();

const onSearch = (searchTerm) => {
  // 이전 검색 쿼리를 중단.
  queryClient.cancelQueries('productSearch');

  // 새로운 검색을 시작.
  queryClient.refetchQueries(['productSearch', searchTerm]);
};

사용 시나리오:

사용자가 '티셔츠'를 검색하려 했지만, 실수로 '티'만 입력하고 검색 버튼 누를 경우
서버는 '티'와 관련된 모든 상품 정보를 가져오기 시작
그런데 사용자는 자신의 실수를 깨닫고 바로 '티셔츠'를  입력하고 다시 검색 버튼을 누를 경우

이런 경우, 첫 번째로 시작된 '티' 검색은 더 이상필요 x. 이제 '티셔츠' 검색이 중요
이때 cancelQueries를 사용하면 '티' 검색을 중단, 새로운 '티셔츠' 검색에 더 집중

 

Mutate, Mutateasync 

// mutate 사용 예
// mutate는 간단한 비동기 작업에 적합
const mutation = useMutation(yourMutationFunction);

mutation.mutate(data);

// mutateAsync 사용 예
// mutateAsync는 결과나 오류에 따른 추가적인 처리가 필요한 경우에 더 적합
const mutation2 = useMutation({ mutationFn: addTodo });

try {
  const todo = await mutation.mutateAsync(todo);
  console.log(todo);
} catch (error) {
  console.error(error);
} finally {
  console.log('done');
}

사용 시나리오:
mutate: 사용자에게 직접적인 피드백이 필요하지 않은 경우나,
성공/실패 여부를 즉시 처리할 필요가 없는 경우에 주로 사용

mutateAsync: 성공/실패에 따라 즉시 특정 동작을 수행, 결과값을 직접 사용하고 싶을 때 유용
예를 들면, form 제출 후 성공/실패 메시지를 바로 보여주는 경우에 사용