React在普通函数中调用自定义Hook触发规则报错该如何解决?
问题原因
你触发了React Hook的调用规则校验,错误和useUrl本身的实现无关,是调用位置不符合要求。
React Hook必须满足两个调用条件:
- 仅能在React函数组件的最顶层调用
- 仅能在其他自定义React Hook的最顶层调用
你在普通事件回调函数handleAddFormation内部调用Hook,不符合规则,因此报错。
另外你当前的useUrl设计也不满足你的需求:
- 现有
useUrl会在Hook被调用时自动通过useEffect触发请求,你需要的是点击事件触发时才发起请求 useUrl不是异步函数,也没有返回Promise,你用await调用不会产生预期的等待效果
修复方案
方案1:封装为普通异步请求函数(推荐,满足你当前的最简需求)
直接把请求逻辑封装为普通工具函数,不需要用到Hook:
// 封装请求工具 export default async function requestUrl(method, url, args) { try { const res = await axios({ method, url, data: args }) return res.data } catch (err) { console.log(err) throw err } }
调用方式:
const handleAddFormation = async () => { console.log('add formation') await requestUrl('POST', 'http://localhost:1337/formations', newFormationList) setNewFormationList([]) setModalOpen(false) }
方案2:改造为可手动触发的Hook(适合需要复用请求状态的场景)
如果你需要在多个组件复用请求的loading、返回数据data、错误error等状态,可以把Hook改造成返回触发函数的形式,在组件顶层调用Hook拿到触发方法,再在回调中执行:
// 改造后的useUrl Hook export default function useUrl() { const [data, setData] = useState([]) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const triggerRequest = useCallback(async (method, url, args) => { setLoading(true) setError(null) try { const res = await axios({ method, url, data: args }) setData(res.data) return res.data } catch (err) { setError(err) console.log(err) throw err } finally { setLoading(false) } }, []) return { data, loading, error, triggerRequest } }
调用方式:
// React组件顶层调用Hook,符合调用规则 const { triggerRequest } = useUrl() const handleAddFormation = async () => { console.log('add formation') await triggerRequest('POST', 'http://localhost:1337/formations', newFormationList) setNewFormationList([]) setModalOpen(false) }
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

