使用 React Hook Form 的 useQuery(来自 React Query)抛出无效的 Hook 调用

useQuery (from React Query) with React Hook Form throws Invalid Hook Call

出现以下错误:

Unhandled Rejection (Error): Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app

我的登录表单

export const SignInView: FC<{ path: string }> = (): ReactElement => {
  type Inputs = {
    userId: string;
  };

 function fetchUser(id: string): UseQueryResult {
  return useQuery('fetchUser', async () => {
    const response: Response = await fetch("http://localhost:8080/users/" + id, RequestInit = {method: 'GET'});
    return response;
  });
}

  const { register, handleSubmit, getValues, errors, setError } = useForm<Inputs>();

  const onSubmit = (): void => {
    const { userId } = getValues();
    //throws Invalid hook call. Hooks can only be called inside of the body of a function component
    const { data } = fetchUser(userId);
   //....some logic here.
}

return (
    <div className='container container-rounded border w-25 bg-white text-center'>
      <div className='row p-2 mt-2 text-center'>
        <div className='col'>
          <p className='h3' data-content='header'>
            Demo
          </p>
        </div>
      </div>

      <div className='row p-2'>
        <div className='col'>
          <h5>Sign in</h5>
        </div>
      </div>

      <Form onSubmit={handleSubmit(onSubmit)}>
        <div className='row'>
          <div className='col form-group'>
            <Form.Control
              type='text'
              name='userId'
              autoFocus
              ref={register({ required: true })}
              className='form-control form-control-lg'
              placeholder='User ID'
              data-field='userId'
            />
          </div>
        </div>

        <div className='row p-2'>
          <div className='col text-center'>
            <Button
              type='submit'
              className='default btn btn-primary btn-lg btn-block button-rounded'
              data-action='sign-in'>
              Sign in
            </Button>
          </div>
        </div>
      </Form>
)

我看到建议说 useMutation 而是调用 mutate 回调函数,但这是一个 GET 调用,所以 useQuery 在这种情况下更合适。

错误是正确的,因为您尝试调用不在 <SignInView /> 组件主体内的挂钩。

当你从你的 fetchUser 函数返回一个 useQuery 钩子时,它也是一个反应约定,为你的自定义钩子使用“use”前缀,所以你可以只调用它 useUser.

您可以通过手动调用 api 来使您的用例正常工作。只需将查询的 enabled 配置选项设置为 false 并在 onSubmit 回调中使用 refetch 触发获取。

然后使用 RHF 的 watch 将您的 <Form.Control /> 的当前值传递给您的 useUser 挂钩。

function useUser(id: string): UseQueryResult {
  return useQuery('fetchUser', async () => {
    const response: Response = await fetch("http://localhost:8080/users/" + id, RequestInit = {method: 'GET'});
    return response;
  }, { enabled: false });
}
export const SignInView: FC<{ path: string }> = (): ReactElement => {
 const { register, handleSubmit, errors, setError, watch } = useForm<Inputs>();
 const userId = watch('userId');
 const { refetch } = useUser(userId);

 const onSubmit = async (): void => {
  const { data } = await refetch();
  //....some logic here.
 }

return (...);
}