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

React自定义Hook useAxios在按钮点击事件调用报错如何修复

报错原因

你触发的是React官方的Hook规则校验:所有React Hook(包括自定义Hook)只能在函数组件的顶层作用域调用,不能在事件回调、循环、条件判断等非顶层位置调用。
你当前封装的useAxios默认会在组件加载时自动发起请求,不满足点击登录按钮才触发请求的需求,同时你在onFinish提交回调里调用Hook的写法本身就违反规则,所以才会报错。

修复步骤

1. 改造自定义Hook useAxios,支持手动触发请求

调整Hook逻辑,把请求方法暴露出来,同时支持配置是否自动发起请求,适配不同场景:

import { useState, useEffect, useCallback } from 'react';
import axios from 'axios';

axios.defaults.baseURL = 'http://localhost:3000/';

const useAxios = ({ url, method, auto = false, body = null, headers = null }) => {
  const [response, setResponse] = useState(null);
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);

  // 把请求方法暴露出去,支持手动调用,useCallback避免不必要的重渲染
  const fetchData = useCallback(async (customBody = body, customHeaders = headers) => {
    setLoading(true);
    setError('');
    try {
      const res = await axios[method](url, customHeaders, customBody);
      setResponse(res.data);
      return res.data;
    } catch (err) {
      setError(err);
      throw err;
    } finally {
      setLoading(false);
    }
  }, [method, url, body, headers]);

  // 支持配置是否进入组件就自动发起请求,适配页面初始化拉取数据的场景
  useEffect(() => {
    if (auto) {
      fetchData();
    }
  }, [fetchData, auto]);

  return { response, error, loading, fetchData };
};

export default useAxios;

2. 改造LoginForm组件的调用逻辑

在组件顶层调用Hook拿到手动触发方法,提交时再调用即可:

import React from 'react';
import { Form, Input, Button, message } from 'antd';
import useAxios from '../hooks/useAxios';

const LoginForm = () => {
  // 组件顶层调用Hook,配置登录请求基础参数,设置auto为false不自动发请求
  const { fetchData, loading } = useAxios({
    url: 'api/auth/login',
    method: 'post',
    auto: false
  });

  const onFinish = async (body) => {
    try {
      // 提交表单时手动调用请求方法,传入表单参数
      const loginRes = await fetchData(body);
      console.log('登录成功', loginRes);
      message.success('登录成功');
      // 后续可添加存储token、跳转页面等逻辑
    } catch (err) {
      console.error('登录失败', err);
      message.error('登录失败,请检查账号密码');
    }
  };

  const findIDAndPassword = () => {
    console.log('findIDAndPassword');
  };

  return (
    <Form name="basic" onFinish={onFinish} autoComplete="off">
      <Form.Item
        name="id"
        rules={[
          {
            required: true,
            message: '请输入账号!',
          },
        ]}
      >
        <Input placeholder="账号" />
      </Form.Item>
      <Form.Item
        name="password"
        rules={[
          {
            required: true,
            message: '请输入密码!',
          },
        ]}
      >
        <Input.Password placeholder="密码" />
      </Form.Item>
      <Form.Item>
        <Button type="primary" htmlType="submit" block loading={loading}>
          登录
        </Button>
      </Form.Item>
      <Button type="link" block onClick={findIDAndPassword}>
        找回账号密码
      </Button>
    </Form>
  );
};

export default LoginForm;
补充说明

如果仅需要处理登录这一个单次触发的请求,不想修改现有useAxios封装,也可以直接在onFinish里直接调用axios发请求,不需要走自定义Hook,原本的useAxios更适合页面初始化就需要拉取数据的场景,比如列表页加载数据。

内容的提问来源于stack exchange,提问作者고윤태

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 11:45:03