如何修复React中无法终止的递归func()函数?
React递归函数无法终止的闭包问题解决
你的问题核心是React闭包陷阱:
组件第一次渲染时,func函数被创建,它捕获了当时的sum(值为6)和array(值为[1,2,3])。后续通过setArray更新状态后,组件会重新渲染,但之前通过setTimeout排队的递归调用,执行的还是初始版本的func——这个旧函数完全看不到新的状态值,所以sum >=10的终止条件永远不会触发,导致递归无限执行。
解决方案1:用useRef跟踪最新状态
useRef的.current属性是可变的,不会被闭包捕获旧值,我们可以用它同步保存最新的sum和array:
import { useState, useEffect, useRef } from 'react'; function App() { const [array, setArray] = useState([1, 2, 3]); const [sum, setSum] = useState(0); // 定义ref保存最新状态 const sumRef = useRef(sum); const arrayRef = useRef(array); useEffect(() => { const currentSum = array.reduce((acc, curr) => acc + curr, 0); setSum(currentSum); // 同步更新ref的current值 sumRef.current = currentSum; arrayRef.current = array; }, [array]); const getRandNum = () => { const num = Math.floor(Math.random() * 5); setArray(prev => [...prev, num]); }; const func = () => { // 用ref的最新值判断终止条件 if (sumRef.current >= 10) return; setTimeout(() => { getRandNum(); func(); }, 500); }; return ( <> <div className="App"> {/* 给map元素添加key避免React警告 */} {array.map((num, index) => ( <p key={index}>{num}</p> ))} </div> <button onClick={() => func()}>click</button> <p>sum: {sum}</p> </> ); }
解决方案2:用useCallback让函数依赖状态更新
通过useCallback把func的依赖设为sum,这样每次sum变化时,func都会重新创建,确保递归调用的是能拿到最新状态的版本:
import { useState, useEffect, useCallback } from 'react'; function App() { const [array, setArray] = useState([1, 2, 3]); const [sum, setSum] = useState(0); useEffect(() => { setSum(array.reduce((acc, curr) => acc + curr, 0)); }, [array]); const getRandNum = () => { const num = Math.floor(Math.random() * 5); setArray(prev => [...prev, num]); }; // 用useCallback绑定sum为依赖 const func = useCallback(() => { if (sum >= 10) return; const timer = setTimeout(() => { getRandNum(); func(); }, 500); // 清理定时器,避免内存泄漏 return () => clearTimeout(timer); }, [sum]); return ( <> <div className="App"> {array.map((num, index) => ( <p key={index}>{num}</p> ))} </div> <button onClick={() => func()}>click</button> <p>sum: {sum}</p> </> ); }
补充说明
- 方案1更适合跟踪多个状态的场景,方案2更聚焦于状态变化时更新函数,两种都能解决闭包问题。
- 方案2中添加定时器清理函数,防止组件卸载后定时器继续执行造成内存泄漏。
内容的提问来源于stack exchange,提问作者Janez04
相关产品推荐
相关产品推荐

