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

事件处理函数内调用自定义hook报错 寻找useState替代实现方案

改造自定义Hook的核心逻辑

你需要将自动触发请求的useAxiosGet调整为「顶层调用获取状态+手动触发请求」的设计,既符合Hook调用规则,也能满足事件回调中发起请求的需求。

改造后的useAxiosGet实现
import { useState, useCallback } from 'react';
import axios from 'axios';

const useAxiosGet = (defaultUrl = '') => {
  // 统一管理请求相关状态
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  // 触发请求的函数,用useCallback缓存避免不必要的重渲染
  const triggerRequest = useCallback(async (requestUrl = defaultUrl) => {
    // 实现每轮渲染仅触发一次的逻辑:请求进行中直接拦截重复调用
    if (loading) return;
    try {
      setLoading(true);
      const res = await axios.get(requestUrl);
      setData(res.data);
      setError(null);
      return res.data;
    } catch (err) {
      setError(err);
      setData(null);
      throw err;
    } finally {
      setLoading(false);
    }
  }, [loading, defaultUrl]);

  return {
    loading,
    data,
    error,
    triggerRequest
  };
};
组件内使用示例
import { useLongPress } from 'use-long-press';
import { useEffect } from 'react';

function YourComponent() {
  // 组件顶层调用Hook,符合Hook调用规则
  const { loading, data, triggerRequest } = useAxiosGet('/api/your-default-url');

  // 首屏初始化请求:和原有逻辑保持一致
  useEffect(() => {
    triggerRequest();
  }, [triggerRequest]);

  // 长按事件配置
  const longPressBind = useLongPress(() => {
    // 长按触发的逻辑
  }, {
    onCancel: () => {
      // 长按取消事件中直接调用触发函数即可,不会触发Hook调用报错
      triggerRequest('/api/collect-item');
    }
  });

  return (
    <button {...longPressBind}>
      {loading ? '请求中' : '长按操作'}
    </button>
  );
}
原报错原因说明

原有实现是在事件回调中直接调用了useAxiosGet这个Hook函数,违反了React Hook只能在函数组件顶层调用的规则。改造后所有Hook调用都在组件最外层执行,事件回调中仅调用普通的异步请求函数triggerRequest,完全符合React语法规则,同时也保留了请求状态的统一管理能力。

内容的提问来源于stack exchange,提问作者Jon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 20:06:03