React Hooks:如何让函数在每次事件触发时执行(不受状态变化影响)
问题分析与解决方案
问题代码
var [testVar, setTestVar] = useState(0) var showTestVar = () => { console.log(testVar) } var effectTest = () => { setTestVar(1) setInterval(showTestVar, 1000) }
需求
让showTestVar每次被setInterval触发时,都能执行并获取到最新的testVar状态值,无论状态是否变化。
当前问题原因
showTestVar是组件渲染时创建的函数,它通过闭包捕获了当前渲染周期的testVar值。当setTestVar(1)触发组件重新渲染后,会生成一个新的showTestVar函数(捕获了testVar=1),但之前的定时器仍在调用旧的showTestVar(捕获了testVar=0),导致日志同时出现新旧状态值。
解决方案
方案1:使用useRef保存最新状态引用
useRef的.current属性是可变的,不会触发组件渲染,我们可以用它同步最新的状态值,让showTestVar每次调用都能拿到最新值:
import { useState, useRef, useEffect } from 'react'; function TestComponent() { const [testVar, setTestVar] = useState(0); // 用ref保存最新的testVar值 const testVarRef = useRef(testVar); // 状态更新时同步ref useEffect(() => { testVarRef.current = testVar; }, [testVar]); const showTestVar = () => { // 访问ref的current属性获取最新值 console.log(testVarRef.current); }; // 用ref保存定时器ID,方便清理 const intervalRef = useRef(null); const effectTest = () => { // 先清除已有定时器,避免重复创建 if (intervalRef.current) { clearInterval(intervalRef.current); } setTestVar(1); intervalRef.current = setInterval(showTestVar, 1000); }; // 组件卸载时清理定时器,防止内存泄漏 useEffect(() => { return () => { if (intervalRef.current) { clearInterval(intervalRef.current); } }; }, []); return <button onClick={effectTest}>触发测试</button>; }
方案2:直接在定时器回调中读取最新状态(简化版)
如果不需要复用showTestVar函数,可以直接在定时器回调里通过函数式更新获取最新状态:
const effectTest = () => { setTestVar(1); // 用函数式更新读取最新状态,不修改状态 setInterval(() => { setTestVar(prev => { console.log(prev); return prev; // 仅读取,不更新状态 }); }, 1000); };
关键注意点
- 务必清理定时器:每次创建新定时器前清除旧的,组件卸载时也需清除,避免内存泄漏和多个定时器同时运行。
useRef是处理闭包捕获旧值问题的通用方案,适用于需要在异步回调中获取最新状态/属性的场景。
内容的提问来源于stack exchange,提问作者Gene Knight
相关产品推荐
相关产品推荐

