React useEffect触发无限循环警告问题求助(Todo应用开发)
解决React Todo列表清除按钮触发无限循环的问题
问题根源
点击清除按钮后,btn状态变为"clr"触发useEffect执行,而useEffect里调用的deleteCompleted()会更新arr和finishArr状态。由于arr和finishArr是useEffect的依赖项,状态更新后会再次触发useEffect,进而再次调用deleteCompleted(),形成无限循环,最终触发以下警告:
Warning: 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.
解决方案
1. 将清除逻辑移出useEffect,直接绑定到按钮点击事件
不要通过btn状态在useEffect中间接处理清除操作,而是直接把清除函数绑定到按钮的点击事件,切断useEffect和状态更新的循环触发链。
修改后的代码示例:
// 清除按钮点击事件处理 const handleClear = () => { deleteCompleted(); }; // 调整useEffect逻辑,移除对"clr"分支的处理 useEffect(() => { let currentFinalArr = arr; if (btn === "act") { currentFinalArr = findUniqueElements(arr, finishArr); } else if (btn === "com") { currentFinalArr = finishArr; } const newRenderAgain = returnTodos(currentFinalArr); setRenderAgain(newRenderAgain); }, [arr, finishArr, btn]); function deleteCompleted() { const updatedArr = findUniqueElements(arr, finishArr); setArr(updatedArr); setFinishArr([]); }
2. 用useMemo替代renderAgain状态(可选优化)
renderAgain的值完全可以通过arr、finishArr和btn计算得出,不需要单独维护状态。使用useMemo可以避免不必要的状态更新,让代码更简洁高效:
import { useMemo } from 'react'; // 用useMemo推导renderAgain,无需单独设置状态 const renderAgain = useMemo(() => { let currentFinalArr = arr; if (btn === "act") { currentFinalArr = findUniqueElements(arr, finishArr); } else if (btn === "com") { currentFinalArr = finishArr; } return returnTodos(currentFinalArr); }, [arr, finishArr, btn]); // 移除原有的useState和相关setRenderAgain逻辑
关键要点
- 禁止在
useEffect中调用会更新其依赖项状态的函数,否则必然触发无限循环。 - 对于可通过现有状态计算得出的值,优先使用
useMemo而非额外状态变量,减少不必要的重渲染和状态更新。
内容的提问来源于stack exchange,提问作者Ayush
相关产品推荐
相关产品推荐

