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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 00:06:06