[Tanstack Query/Hooks] 네트워크 요청 결과에따라 훅 실행하기

로그인 요청을 서버로 보내고 나서, 성공할 경우 user 정보를 관리하는 zustand store에 정보를 업데이트하기위해 zustand의 훅을 사용했다. 그런데 ESLint에서 아래와같은 오류가 떴다!

 

ESLint: React Hook "useUserStore" is called in function "onSuccess" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use".(react-hooks/ rules-of-hooks)

 

리액트 훅은 컴포넌트나 커스텀 훅의 최상위 레벨에서 사용해야하는데, 내가 사용하려는 위치인 onSuccess는 컴포넌트도, 커스텀훅도 아니라는 의미다. (조건부로 호출되거나 콜백함수에서 호출할 수 없음, 상태가 꼬인다)

 

처음에는 단순히 useSignIn이 아닌 회원가입 페이지 컴포넌트에서 처리할까 생각했다. 하지만 요청에 성공했을 때 처리해야하는 로직은 Tanstack Query 로직과 더 연관되어있기 때문에 useSignIn 내부에 있는 것이 적절하고, 회원가입 페이지 컴포넌트에서는 사용자와 상호작용할 UI 관련 처리를 해주는 것이 맞다는 생각이 들었다.

그럼 특별히 이 컴포넌트가 아니어도 로그인 로직을 사용할 때 중복 처리하지않고 사용할 수도 있고!

 

해결 방법은 단순했다 ㅎㅎㅎ

조건부로 실행되지 않는 컴포넌트 혹은 커스텀훅의 최상위에서 실행되어야하므로, useUserStore에서 받아 사용할 signIn을 useSignIn 최상위에서 받아오고 signIn 함수 사용만 onSuccess에서 하도록 했다.

 

아래는 전/후 코드다.

 

수정 전

export const useSignIn = () => {
  const { mutate, isPending, error, isError, isSuccess } = useMutation({
    mutationFn: postSignIn,
    onSuccess: (data) => {
      const { username, nickname, accessToken } = data[0];
      const { signIn } = useUserStore((state) => state);  // 조건부로 실행되는 onSuccess의 콜백에서 훅을 호출하고 있음
      signIn({ username, nickname, accessToken });
    },
    onError: (error) => {
      console.log('Sign In Error: ', error);
    },
  });

  return { mutate, isPending, error, isError, isSuccess };
};

 

 

수정 후

export const useSignIn = () => {
  const { signIn } = useUserStore((state) => state);
  const { mutate, isPending, error, isError, isSuccess } = useMutation({
    mutationFn: postSignIn,
    onSuccess: (data) => {
      const { username, nickname, accessToken } = data[0];
      signIn({ username, nickname, accessToken });
    },
    onError: (error) => {
      console.log('Sign In Error: ', error);
    },
  });

  return { mutate, isPending, error, isError, isSuccess };
};