事件处理函数内调用自定义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
相关产品推荐
相关产品推荐

