NextJS项目onSubmit内调用自定义hook报Invalid Hook Call错误如何解决?
错误根因
你的报错核心是违反React Hook的调用规则:Hook只能在React函数组件的顶层作用域调用,不能在事件回调、循环、条件判断这类非渲染阶段的逻辑里调用,你在onSubmit回调中调用自定义Hook自然会触发非法Hook调用错误。
你之前提前在组件顶层调用Hook但token无法同步的问题,是因为你把请求参数固定在了Hook初始化时机,没有做动态触发逻辑,同时SWR默认是自动触发请求模式,不符合手动提交的需求。
解决方案
1. 改造自定义Hook为手动触发模式
调整Hook逻辑,所有内置Hook依然在顶层调用,新增手动触发请求的普通方法暴露给外部,同时通过useSelector实时获取Redux最新token,解决token不同步问题:
import { useState } from 'react' import useSWR from 'swr' import { useSelector } from 'react-redux' import axios from 'axios' function useApiPost() { const [data, setData] = useState(null) const [error, setError] = useState(null) // 实时同步Redux最新token,token更新时会自动同步到Hook内 const token = useSelector(state => state.user.token) // 初始化时关闭自动请求,设置为纯手动模式 const { mutate, isLoading } = useSWR( null, null, { revalidateOnFocus: false, revalidateOnMount: false } ) // 暴露给外部的请求触发方法,动态接收地址和参数 const trigger = async (resource, params) => { const { url, data: inData } = rest(resource, params) if (!token) { const err = new Error('用户未授权') setError(err) throw err } try { const res = await mutate( url, () => axios.request({ url, method: 'post', data: inData, headers: { Authorization: `Bearer ${token}` } }).then(res => res.data), { revalidate: true } ) setData(res) return res } catch (err) { setError(err) throw err } } return { data, error, trigger, isLoading } }
2. 组件内正确调用
在组件顶层调用改造后的Hook,onSubmit回调中仅调用返回的普通异步方法即可:
// 组件顶层调用所有Hook const { register, errors, handleSubmit, setValue, reset, control } = useForm() const { trigger: postUpdate, data: updateRes, error: updateError } = useApiPost() const onSubmit = async (data) => { try { // 表单校验通过后手动触发请求 const newData = await postUpdate(`users/update/${id}`, data) // 写请求成功后的后续逻辑 } catch (err) { // 写请求失败的异常处理逻辑 } } return ( <form onSubmit={handleSubmit(onSubmit)}> {/* 表单其余内容 */} </form> )
适配改造说明
- 如果需要PUT/DELETE等其他请求方法,按相同逻辑改造对应的Hook即可
- 返回的
isLoading状态可直接用于表单提交的加载态展示 - 所有Hook调用都符合React规则,token会实时同步Redux最新值,不会出现携带过期token的问题
内容的提问来源于stack exchange,提问作者user2833257
相关产品推荐
相关产品推荐

