React如何避免useEffect内调用函数触发最大更新深度超限错误
Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
问题根因
- 父组件定义的
pushToArrayOfDocuments函数未做稳定化处理,每次父组件渲染时都会生成全新的函数实例。该函数作为setDocument属性传给子组件后,会被识别为依赖变更,触发子组件的useEffect执行。 - 子组件useEffect执行
setDocument(file)后会更新父组件的arrayOfDocuments状态,导致父组件重新渲染,再次生成新的pushToArrayOfDocuments实例,形成无限渲染循环。
解决方案
1. 用useCallback稳定父组件函数引用
在父组件中使用useCallback包裹pushToArrayOfDocuments,因为函数内部调用setArrayOfDocuments时使用了函数式更新,不依赖外部状态,所以依赖数组可以留空,确保函数引用永远不变:
import { useCallback, useState } from 'react'; // 原有状态定义不变 const [arrayOfDocuments, setArrayOfDocuments] = useState([]); // 用useCallback包裹函数 const pushToArrayOfDocuments = useCallback((obj) => { if (obj.filename && obj.file && obj.expiredate && obj.doctype) { setArrayOfDocuments((oldArr) => { const arr = oldArr.slice(); const index = arr.map((e) => e.filename).indexOf(obj.filename); if (index !== -1) { arr[index] = obj; } else { arr.push(obj); } return arr; }); } }, []);
2. 子组件useEffect增加变更校验(可选优化)
如果file是引用类型对象,可在useEffect中增加有效性判断,只有当file真的发生业务层面的变更时才调用setDocument,避免无效触发:
useEffect(() => { // 用filename作为唯一标识判断是否真的有变更,也可根据业务需要替换为深比较 if (file?.filename !== document?.filename) { setDocument(file); } }, [file, setDocument, document]);
内容的提问来源于stack exchange,提问作者Singh
相关产品推荐
相关产品推荐

