如何调整React自定义hook让useEffect内API请求仅执行一次
问题根因
- 依赖数组配置错误:你当前的useEffect依赖包含了
data和fetchFunction两个不稳定变量:- 请求成功后
setData会触发data更新,直接导致useEffect二次执行 - 若传入的
getPercentageRead、getNotes未做引用稳定处理,每次组件渲染都会生成新的函数引用,同样会触发useEffect重新执行
- 请求成功后
- 请求触发逻辑冗余:用
data === null判断是否发起请求的逻辑,和不稳定依赖叠加后,很容易重复触发请求 - (可选)React18+ 开发环境严格模式默认会执行两次useEffect用于检测副作用泄漏,也会导致开发环境下请求重复,生产环境会自动恢复正常。
修复方案
第一步:修改自定义hook useFetchMongoField
import { useState, useEffect, useRef } from 'react'; const useFetchMongoField = (user, id, fetchFunction) => { const [hasFetched, setHasFetched] = useState(false); const [data, setData] = useState(null); const [error, setError] = useState(null); // 用于标记请求是否已经发起,不受重渲染影响,避免重复请求 const hasRequestedRef = useRef(false); useEffect(() => { // 无有效用户、已经发起过请求、已经拉取到数据,都直接返回 if (!user || hasRequestedRef.current || hasFetched) return; const abortController = new AbortController(); const fetchData = async () => { hasRequestedRef.current = true; try { let result = await fetchFunction(user.email, id, abortController.signal); // 组件未卸载才更新状态 if (!abortController.signal.aborted) { setData(result); setHasFetched(true); } } catch (error) { if (!abortController.signal.aborted) { setError(error.message); } } }; fetchData(); // 组件卸载时中止请求,避免内存泄漏 return () => abortController.abort(); // 仅保留必要的稳定依赖 }, [user, id, fetchFunction, hasFetched]); return { data, hasFetched, error }; };
修改说明:
- 新增
hasRequestedRef引用标记请求状态,彻底避免同一hook实例重复发起请求 - 移除依赖数组中的
data,避免请求成功后触发副作用重新执行 - 新增
AbortController处理请求中止,避免组件卸载后仍执行状态更新的报错 - 用
hasFetched和ref双重判断请求触发条件,逻辑更严谨
第二步:稳定传入的请求函数引用
如果getPercentageRead、getNotes是在组件内部定义的,需要用useCallback包裹函数,保证依赖不变的情况下函数引用不会刷新,示例:
const getPercentageRead = useCallback(async (email, isbn, signal) => { // 原有请求逻辑,可传入signal用于中止请求 const res = await fetch(`/api/read-percentage?email=${email}&isbn=${isbn}`, { signal }); return res.json(); }, []); const getNotes = useCallback(async (email, isbn, signal) => { // 原有请求逻辑 const res = await fetch(`/api/notes?email=${email}&isbn=${isbn}`, { signal }); return res.json(); }, []);
内容的提问来源于stack exchange,提问作者Ludwig
相关产品推荐
相关产品推荐

