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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:37:40