小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
翻译自:beta.reactjs.org/learn/refer…
当你希望组件“记住”一些信息,但是你不希望这些信息触发重新 render 的时候,你可以使用 ref,它像一个秘密的“口袋”,用于在组件中存储信息。
系列文章
useRef 简单易懂解析(二)useRef 的例子
示例:构建秒表
你可以在单个组件中结合使用 refs 和 state。例如,让我们制作一个秒表,用户可以通过按按钮来启动或停止它。为了显示从用户按下 “Start” 以来已经过去了多长时间,你需要跟踪按下 “Start” 按钮的时间以及当前时间。这些信息是用于渲染的,所以你可以把它保存在 state 里面:
const [startTime, setStartTime] = useState(null);
const [now, setNow] = useState(null);
当用户按下 “Start” 时,你将使用 setInterval 每 10 毫秒更新一次时间,就像下面的例子:
import { useState } from 'react';
export default function Stopwatch() {
const [startTime, setStartTime] = useState(null);
const [now, setNow] = useState(null);
function handleStart() {
// 开始计时
setStartTime(Date.now());
setNow(Date.now());
setInterval(() => {
// 每 10ms 更新一次时间
setNow(Date.now());
}, 10);
}
let secondsPassed = 0;
if (startTime != null && now != null) {
secondsPassed = (now - startTime) / 1000;
}
return (
<>
<h1>Time passed: {secondsPassed.toFixed(3)}</h1>
<button onClick={handleStart}>
Start
</button>
</>
);
}
当按下 “Stop” 按钮时,你需要取消现有的 interval,用来停止更新 now 这个 state。你可以调用 clearInterval 来实现,但是你需要给它一个 interval ID,这个 ID 以前是在用户按下 Start 时由 setInterval 调用返回的。你需要把 interval ID 保存在某个地方。由于 interval ID 不用于渲染,你可以将它保存在ref中:
import { useState, useRef } from 'react';
export default function Stopwatch() {
const [startTime, setStartTime] = useState(null);
const [now, setNow] = useState(null);
const intervalRef = useRef(null);
function handleStart() {
setStartTime(Date.now());
setNow(Date.now());
intervalRef.current = setInterval(() => {
setNow(Date.now());
}, 10);
}
function handleStop() {
clearInterval(intervalRef.current);
}
let secondsPassed = 0;
if (startTime != null && now != null) {
secondsPassed = (now - startTime) / 1000;
}
return (
<>
<h1>Time passed: {secondsPassed.toFixed(3)}</h1>
<button onClick={handleStart}>
Start
</button>
<button onClick={handleStop}>
Stop
</button>
</>
);
}
当一个信息用于渲染时,把它保存在 state 中。当一个信息只被事件处理程序需要,并且改变它不需要 re-render 时,使用 ref 可能更有效。