使用 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 (...);
}
出现以下错误:
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 (...);
}