React-query mutation 함수의 매개변수 타입 에러 (문제 해결)

Devinix·2023년 9월 6일
3

[문제 해결]

목록 보기
1/29
post-thumbnail

개요

react-query의 useMutation 훅을 사용하여 api 호출을 처리하려고 할 때, 에러가 발생하는 것을 발견했다. 이 에러는 mutation 함수의 매개변수에서 발생했다. 에러메세지를 보기 이전에 코드를 살펴보자.


우선, react-query 라이브러리로 api통신을 하기 위해서는

  1. api를 통신하는 함수 코드
  2. react-query 코드

두 가지 주요 부분이 필요하다. 우선, api를 통신하는 함수를 선언하는 코드(1번의 내용)부터 살펴보도록 하자.


// axios를 사용한 api 통신 함수 선언

const updateGroupApi = (
  groupName: string | undefined,
  newGroupName: string | undefined,
  email: string
): Promise<AxiosResponse> => {
  try {
    const data = {
      groupname: groupName,
      newgroupname: newGroupName,
      email: email,
    };
    const response = axios.patch("/itemgroup.update", data);
    return response;
  } catch (error) {
    console.log(error);
    throw error;
  }
};

updateGroupApi라는 이름으로 함수를 하나 만들어 주었다. 이 함수는 그룹 이름을 업데이트하기 위한 api 호출을 수행하는 함수이다. 그룹의 기존 이름, 새 이름, 이메일을 매개변수로 받아 세 개의 파라미터를 하나의 데이터로 묶어서 서버에 전달해 patch 요청을 수행하고, 응답을 반환하거나 오류를 처리한다. 이 부분에는 아무런 문제가 없다.


문제의 react-query 부분의 코드(2번의 내용)를 보자.


  const updateGroupMutation = useMutation({
    mutationFn /*에러 발생!!*/: (
      groupName: string | undefined,
      newGroupName: string | undefined
    ) => {
      return updateGroupApi(groupName, newGroupName, values.email);
    },
    onSuccess: (data) => {
      console.log(data);
    },
  });

React-query의 useMutation 훅을 사용하여 updateGroupApi라는 Api 통신 함수를 호출하고 있다. 이때, mutationFn 함수는 groupName과 newGroupName 두 개의 매개변수를 받는다. 이 매개변수들은 순서대로 updateGroupApi에 전달되며, updateGroupApi의 세번째 인자는 values.email이다. 이 values.email 값은 updateGroupApi 함수에서 필요한 실제 email 값이다.

문제 상황

react-query의 useMutation 훅을 사용하여 API 호출을 처리하려고 할 때, 다음과 같은 타입 오류가 발생했다.

이 호출과 일치하는 오버로드가 없습니다.
마지막 오버로드에서 다음 오류가 발생했습니다.
'{ mutationFn: (groupName: string | undefined, newGroupName: string | undefined) => 
Promise<AxiosResponse<any, any>>; onSuccess: (data: any) => void; }' 형식의 인수는 'MutationKey' 형식의 매개 변수에 할당될 수 없습니다. 
개체 리터럴은 알려진 속성만 지정할 수 있으며 'readonly unknown[]' 형식에 'mutationFn'() 없습니다.ts(2769) 
useMutation.d.ts(6, 25): 여기서 마지막 오버로드가 선언됩니다. 
(property) mutationFn?: MutationFunction<AxiosResponse<any, any>, string | undefined> | undefined

원인

이 문제의 원인은 mutationFn에 여러 개의 매개변수를 직접 전달했던 것이었다. useMutation은 mutation 함수에 전달되는 매개변수를 하나만 받도록 설계되어 있다.(useQuery의 queryFn도 마찬가지) 이는 react-query의 설계 철학 중 하나인 "유연성"에 기인한다. 다양한 형태의 데이터나 매개변수를 전달해야 할 수 있기 때문에, 함수에 여러 개의 매개변수를 전달하는 대신 하나의 객체로 묶어서 전달하는 것이 더 유리하다. 왜냐하면 이 객체 안에는 필요한 모든 정보나 데이터를 담을 수 있기 때문에 확장성과 유연성이 높아지기 때문이다.

이 방식의 또 다른 이점은 TypeScript와의 통합이다. 객체로 매개변수를 묶는 것은 타입을 정의하고 검증하는 데 있어 더 명확하고 정확하다. 개별 매개변수를 사용할 때보다 객체를 사용하는 것은 타입 오류를 줄이고 코드의 안정성을 높일 수 있다.

해결 과정

이 규칙을 깨닫고 나니, 해결책은 눈에 띄게 간단해 보였다. mutationFn에 전달되었던 여러 매개변수를 하나의 객체로 결합하면 된다. 이에 대한 잘못된 코드와 올바른 코드, 그리고 수정된 나의 코드를 예시로 살펴보도록 하겠다.


잘못된 코드

  const mutation = useMutation({
    mutationFn: (param1: any, param2: any, param3: any) => {
      // ....
    },
  });

올바른 코드

  interface IMutationParams {
    param1: any;
    param2: any;
    param3: any;
  }
  
  const mutation = useMutation({
    mutationFn: ({ param1, param2, param3 }: IMutationParams) => {
      // ....
    },
  });

수정된 나의 react-query 코드

  interface IUpdateGorupMutation {
    groupName: string | undefined;
    newGroupName: string | undefined;
  }

  const updateGroupMutation = useMutation({
    mutationFn: ({ groupName, newGroupName }: IUpdateGorupMutation) => {
      return updateGroupApi(groupName, newGroupName, values.email);
    },
    onSuccess: (data) => {
      console.log(data);
    },
  });

결론

useMutation의 mutationFn은 여러 개의 매개변수를 직접적으로 받아들이지 않는다. 대신, 필요한 모든 매개변수들을 하나의 객체로 결합하면 문제 없이 정상 작동한다. 이러한 접근 방식은 함수의 매개변수 관리를 더욱 유연하게 해주며, 타입에 대한 안정성을 강화시켜 준다. 이 경험을 통해 여러 매개변수를 하나의 객체로 전달하는 설계 방식의 장점을 이해할 수 있었다.

!! 이 특징은 useMutation의 mutationFn에서 post, put, patch, delete와 같은 작업을 처리할 때 뿐만 아니라, get 작업을 다루는 useQuery의 queryFn에서도 동일하게 적용된다는 것을 알아두자. !!

profile
프론트엔드 개발

1개의 댓글

comment-user-thumbnail
2024년 1월 29일

감사합니다 많은 도움 됐습니다.

답글 달기