You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 03:45:03