【发布时间】:2021-11-23 11:26:06
【问题描述】:
根据 React 文档以及关于计时器的 stackoverflow 上的每个示例,人们使用类似于选项 2 w/useEffect (+useState) 的方法来创建可以启动/暂停/重置的计时器。
不过,我也可以通过仅使用 useState 在选项 1 中创建计时器。
为什么没有人依赖 useState 作为计时器?我知道 useEffect 在卸载/重新渲染期间会进行清理,但这真的可以提高性能吗?从 useEffect 不断卸载和重新安装然后调用 setValue 不会比仅执行调用 setValue 的常规函数慢吗?这两个选项都可以调用 clearInterval,所以这两个选项都不足以进行清理吗?
另外,哪个计时器更“准确”,选项 1 还是 2?我相信我了解异步函数的事件循环是如何工作的,但是在 React 中它对我来说有点模糊。是否会出现多个异步函数积压并以某种方式延迟 useEffect 触发并使选项 2 中的计时器以比选项 1 慢的速率滴答的情况(即不是每秒准确滴答并且缓慢落后于另一个计时器)?
谢谢!
选项 1 - 常规函数 + useState
const [time, setTime] = useState(1500);
const [startPauseBtnText, setStartPauseBtnText] = useState('START');
const timeID = useRef(null);
const startPauseTime = () => {
if (timeID.current) {
clearInterval(timeID.current);
timeID.current = null;
setStartPauseBtnText('START');
} else {
timeID.current = setInterval(() => {
setTime((prevTime) => {
return prevTime - 1;
});
}, 1000);
setStartPauseBtnText('PAUSE');
}
};
const resetTime = () => {
clearInterval(timeID.current);
timeID.current = null;
setTime(1500);
};
选项 2 - useEffect + useState
const [isActive, setIsActive] = useState(false);
const [time2, setTime2] = useState(1500);
useEffect(() => {
let timeID2;
if (isActive) {
timeID2 = setInterval(() => {
setTime2((prevTime) => {
return prevTime - 1;
});
}, 1000);
}
return () => clearInterval(timeID2);
}, [isActive, time2]);
const resetTime2 = () => {
setIsActive(false);
setTime2(1500);
};
【问题讨论】:
-
我认为它们都是您需要的选项 - 请参阅 this
-
关注点分离:
useState按照惯例是供您(以及任何其他使用 React 代码的人)包含组件状态的,即 the data that its render behaviour is tied to。计时器不是其中的一部分,它们独立于组件的状态。它们可能触发状态更改,但计时器和它们的值都不是状态,并且状态对于您可能使用的任何和所有变量都不是一个方便的数据存储。也就是说:这里的权威是 React 文档和 React 开发人员。其他人都有自己的看法。 -
感谢迈克的快速回复。但是,选项 1 和 2 都在 setInterval 方法中使用 setVaue,主要区别在于一个由 useEffect 触发,另一个由常规函数触发,因此不完全理解关注点分离在这里的相关性。赞赏任何清晰度。
-
第二部分是为什么
useEffect首先存在as per the docs:“useEffect做什么?通过使用这个Hook,你告诉反应你的组件在渲染后需要做一些事情。” 这当然是调度计时器的情况:这不是渲染的一部分,这是你想要触发的副作用。
标签: reactjs