这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
翻译自:beta.reactjs.org/learn/refer…
当你希望组件“记住”一些信息,但是你不希望这些信息触发重新 render 的时候,你可以使用 ref,它像一个秘密的“口袋”,用于在组件中存储信息。
后面的文章主要是通过一些例子检验对 ref 的理解,实际在 react 官方博客上可以执行调试,文章主要是分析,可以对照着看:beta.reactjs.org/learn/refer…
系列文章
修复坏掉的聊天输入框(Fix a broken chat input)
挑战 1(共 4 个):修复坏掉的聊天输入框
输入一些信息并且单击 “Send”。您会注意到在看到 “Sent!” 提示框之前有 3 秒的延迟。在这个延迟期间,你可以看到一个 “Undo” 按钮,点击它。这个 “Undo” 按钮应该停止 “Sent!” 提示的弹出,它通过使用 handleSend 期间保存的 timeout ID 调用 clearTimeout 来完成这个操作。但是,即使在单击“Undo”后,“Sent!” 消息仍然出现。找出它不起作用的原因,并修复它。
import { useState } from 'react';
export default function Chat() {
const [text, setText] = useState('');
const [isSending, setIsSending] = useState(false);
let timeoutID = null;
function handleSend() {
setIsSending(true);
timeoutID = setTimeout(() => {
alert('Sent!');
setIsSending(false);
}, 3000);
}
function handleUndo() {
setIsSending(false);
clearTimeout(timeoutID);
}
return (
<>
<input
disabled={isSending}
value={text}
onChange={e => setText(e.target.value)}
/>
<button
disabled={isSending}
onClick={handleSend}>
{isSending ? 'Sending...' : 'Send'}
</button>
{isSending &&
<button onClick={handleUndo}>
Undo
</button>
}
</>
);
}
来想一想如何修复吧~~
5
4
3
2
1
提示:像 let timeoutID
这样的常规变量不能在 re-render 之间“存活”,因为每次 render 都从头开始运行组件(并初始化它的变量)。是否应该将 timeoutID 保存在其他地方?
当组件 re-render 时(比如 set state 时),所有的局部变量都要从头初始化。这就是为什么不能将 timeout ID 保存在一个本地变量(如 timeoutID )中,然后期望将来另一个事件处理程序“看到”它。相反,将它存储在 ref 中,React 将在呈现之间保留该 ref。
下面我们来看修改后的结果:
import { useState, useRef } from 'react';
export default function Chat() {
const [text, setText] = useState('');
const [isSending, setIsSending] = useState(false);
const timeoutRef = useRef(null); // 这里保存在 ref 中
function handleSend() {
setIsSending(true);
timeoutRef.current = setTimeout(() => { // 设置 ref 的 current 属性
alert('Sent!');
setIsSending(false);
}, 3000);
}
function handleUndo() {
setIsSending(false);
clearTimeout(timeoutRef.current); // 这里
}
return (
<>
<input
disabled={isSending}
value={text}
onChange={e => setText(e.target.value)}
/>
<button
disabled={isSending}
onClick={handleSend}>
{isSending ? 'Sending...' : 'Send'}
</button>
{isSending &&
<button onClick={handleUndo}>
Undo
</button>
}
</>
);
}