Next.js13中React Hook Form提交函数调用自定义Hook报错问题
解决方案:React Hook规则限制及修复方法
问题根源
你遇到的错误是违反了React Hook核心规则导致的:Hook只能在函数组件或自定义Hook的顶层作用域调用,不能嵌套在事件处理函数(比如onSubmit)、条件判断、循环等代码块中。React依赖Hook的调用顺序跟踪状态,一旦打破这个顺序,就会抛出Invalid hook call错误。
修复方案一:修改自定义Hook,返回可调用的请求函数
调整usePost的设计,让它返回一个可在事件中调用的异步函数,既符合Hook规则,又能在表单提交时触发API调用。
调整后的src/hooks/use-api.ts:
import { useState } from 'react'; export const usePost = () => { const [loading, setLoading] = useState(false); const [error, setError] = useState<Error | null>(null); // 定义可复用的post请求函数 const post = async (url: string, data: any) => { setLoading(true); setError(null); try { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (!response.ok) { throw new Error(`请求失败:${response.statusText}`); } return await response.json(); } catch (err) { const error = err as Error; setError(error); throw error; // 抛出错误让组件层面处理 } finally { setLoading(false); } }; return { post, loading, error }; };
组件中的用法:
import { useForm } from 'react-hook-form'; import { usePost } from '@/src/hooks/use-api'; export default function SubmitForm() { // 在组件顶层调用Hook,拿到post函数和状态 const { post, loading, error } = usePost(); const { register, handleSubmit } = useForm(); const onSubmit = async (formData: any) => { try { // 在表单提交时调用post函数 const result = await post('/api/your-endpoint', formData); // 处理请求成功逻辑,比如弹窗提示、页面跳转 console.log('提交成功:', result); } catch (err) { // 处理请求失败逻辑 console.error('提交失败:', err); } }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="用户名" /> <input {...register('password')} type="password" placeholder="密码" /> <button type="submit" disabled={loading}> {loading ? '提交中...' : '提交'} </button> {error && <p className="text-red-500">{error.message}</p>} </form> ); }
修复方案二:将API请求封装为普通函数(不使用Hook)
如果不想修改现有Hook结构,可以把POST请求逻辑抽成独立的普通函数,在组件中直接调用,同时自行维护loading和error状态。
新建src/services/api.ts:
export const postRequest = async (url: string, data: any) => { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (!response.ok) { throw new Error(`请求失败:${response.statusText}`); } return await response.json(); };
组件中的用法:
import { useState } from 'react'; import { useForm } from 'react-hook-form'; import { postRequest } from '@/src/services/api'; export default function SubmitForm() { const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const { register, handleSubmit } = useForm(); const onSubmit = async (formData: any) => { setLoading(true); setError(null); try { const result = await postRequest('/api/your-endpoint', formData); console.log('提交成功:', result); } catch (err) { setError((err as Error).message); console.error('提交失败:', err); } finally { setLoading(false); } }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="用户名" /> <input {...register('password')} type="password" placeholder="密码" /> <button type="submit" disabled={loading}> {loading ? '提交中...' : '提交'} </button> {error && <p className="text-red-500">{error}</p>} </form> ); }
内容的提问来源于stack exchange,提问作者Kishan Bhensadadiya
相关产品推荐
相关产品推荐

