React状态快照与重渲染疑问:为何setTimeout读取初始state?
React useState 闭包陷阱解析
你遇到的问题核心是React组件渲染时的闭包捕获机制,下面拆解原因和解决方法:
你的理解误区
你对重渲染和state更新的大部分判断是对的,但忽略了一个关键点:setTimeout的回调函数会通过闭包捕获它被创建时所在渲染周期的state值,和后续重渲染的state无关。
具体到这个组件的执行流程:
- 初始渲染时,
text为空字符串,此时生成的handleSend函数里,setTimeout的回调捕获的是这个初始的text值。 - 输入框输入内容触发重渲染,
text更新为新值,组件会生成新的handleSend函数,这个新函数里的回调会捕获更新后的text。 - 但如果是在初始渲染阶段点击了Send按钮,此时调用的是初始版本的
handleSend,它的回调已经绑定了初始的text。哪怕后续你修改输入框触发了多次重渲染,已经被setTimeout注册的回调不会更新,3秒后执行时依然会弹出初始值。
解决方法:使用useRef
useRef创建的引用对象,它的current属性是可变的,不会被闭包固定住取值,每次访问都会拿到最新的值。修改后的代码如下:
import { useState, useRef } from 'react'; export default function Chat() { const [text, setText] = useState(''); const textRef = useRef(''); // 同步ref与state的最新值 textRef.current = text; function handleSend() { setTimeout(() => { alert('Sending: ' + textRef.current); }, 3000); } return ( <> <input value={text} onChange={e => setText(e.target.value)} /> <button onClick={handleSend}>Send</button> </> ); }
每次组件重渲染时,textRef.current都会被更新为最新的text值,所以3秒后回调执行时,访问到的就是修改后的最新内容。
内容的提问来源于stack exchange,提问作者DucanoidYoung
相关产品推荐
相关产品推荐

