正如 React 文档中提到的,React 使用渲染时的当前状态来拍摄 UI 的快照。任何状态更改都会导致新的重新渲染。
因此,定时在打印状态变量之后一段时间执行的警报,会在警报最初计划调用时打印状态变量的值。但是,当同一警报计划打印参考变量时,它会打印该瞬时存在的参考变量的值。 这是代码:
import { useState, useRef } from 'react';
export default function Chat() {
const [text, setText] = useState('');
const dummy = useRef("");
dummy.current = text;
function handleSend() {
setTimeout(() => {
alert('Sending: ' + text);
}, 5000);
}
return (
<>
<input
value={text}
onChange={(e)=>setText(e.target.value)}
/>
<button
onClick={handleSend}>
Send
</button>
</>
);
}
在此代码中,当单击“发送”按钮后更改输入时,警报会显示按“发送”之前最初的文本值,从 React 拍摄快照的事实可以明显看出。但是,当我们用 dummy.current 替换警报中的文本时,警报会在触发警报之前打印输入的最终值。 React 如何调度和替换超时函数的值以及状态变量和引用变量的替换有何不同?
如果我正确地阅读你的问题,你可能不熟悉闭包的概念。你在这里看到的行为并不与 React 绑定,而是与 JS 本身绑定。
在 JS 中,函数形成闭包:创建闭包时范围内的任何局部变量都将被复制,并且其副本将保留在闭包中。这就是为什么即使在“聊天”执行完成后,您的 setTimeout 处理程序也可以显示“聊天”组件中的“文本”变量。
“text”和“dummy.current”行为不同的原因是因为“text”是字符串原语而“dummy”是引用。
当被闭包捕获时,原语和引用都将被复制到闭包中,但是!参考资料 POINT。基元保存数据。
当 setTimeout 处理程序访问“text”变量时,它会访问调用“handleSend”时捕获的原始数据。当 setTimeout 处理程序访问“dummy.current”变量时,它访问该对象的引用,该引用是指向文本原始数据的内存地址。
在下图中,我展示了以下场景: 我输入单词“DOG”并按发送。在我输入“CATS”一词并按发送后。然后两个“setTimeout”将在初始化后5秒触发。
当使用“TEXT”时,由于闭包捕获原始字符串,第一个警报将显示“DOG”,然后第二个警报将显示“CATS”。
当使用“DUMMY.CURRENT”时,当闭包捕获字符串的引用时,两个alert都会查找引用指向的值并显示它,在本例中:“CATS”。
我希望它能让事情变得更清楚。