React中useContext搭配useEffect出现无限循环如何修复?
无限循环触发原因
- Context引用不稳定:
PetProvider每次渲染时,都会生成全新的value对象,同时fetchHandler、registerHandler两个函数也会重新创建,最终导致每次获取到的petsContext引用都不相同。 - useEffect依赖不合理:
Pets组件的useEffect把整个petsContext对象作为依赖项,只要context引用变化就会重新执行副作用。 - 连锁更新形成循环:副作用执行
onFetch拉取数据成功后,会dispatch更新pets状态,触发PetProvider重渲染,再次生成新的context对象,又触发useEffect执行,形成无限循环。 - 隐藏错误:
useReducer的初始化参数写法错误,第二个参数需要直接传入初始状态initialState,你当前传入的是{petReducer, initialState},会导致初始状态不符合预期。
修复方案
第一步:修正useReducer的初始化写法
修改PetProvider中useReducer的调用代码:
// 错误写法 const [petState, dispatchPetAction] = useReducer(petReducer, { petReducer, initialState, }); // 正确写法 const [petState, dispatchPetAction] = useReducer(petReducer, initialState);
第二步:稳定Context的引用
在PetProvider中用useCallback包裹处理函数,用useMemo包裹context的value对象,避免每次渲染生成新的引用:
import React, { useReducer, useCallback, useMemo } from 'react'; // ... 省略其他不变代码 const registerHandler = useCallback(async (first_name, last_name, breed, age, weight) => { // 原有逻辑保持不变 }, []); const fetchHandler = useCallback(async () => { // 原有逻辑保持不变 }, []); // 用useMemo缓存context value const contextValue = useMemo(() => ({ pets: petState.pets, onRegister: registerHandler, onFetch: fetchHandler, }), [petState.pets, registerHandler, fetchHandler]); return ( <PetContext.Provider value={contextValue}> {props.children} </PetContext.Provider> );
第三步:优化Pets组件的useEffect依赖
不要把整个context对象作为依赖,只声明需要用到的onFetch即可,如果你确定只需要在组件挂载时拉取一次数据,也可以直接传空数组作为依赖:
const petsContext = useContext(PetsContext); useEffect(() => { petsContext.onFetch(); }, [petsContext.onFetch]); // 仅需要挂载拉取时可写为[]
内容的提问来源于stack exchange,提问作者Michael Torres
相关产品推荐
相关产品推荐

