javascript - 为什么每次都使用 useEffect 清理日志记录?
问题描述
当用户导航到下一个屏幕以避免它的工作时,我正在实现倒计时并使用useRef
钩子在清理 setTimeout 时使用它cancel all subscription warning
!
但是计数时我有一些奇怪的东西 - 1 我可以在控制台中看到“嘿”!虽然没有清理 setTimeOut!
在这种情况下我不想清理它,但为什么每次计数更改时都要登录!
代码片段
const [seconds, setSeconds] = useState(40);
const countRef = useRef(seconds);
useEffect(() => {
if (seconds > 0) {
countRef.current = setTimeout(() => {
setSeconds(seconds - 1);
}, 1000);
} else {
setSeconds(0);
}
return () => {
console.log('hey'); // every count down it's appeared
clearTimeout(countRef.current);
};
}, [seconds]);
解决方案
您看到“嘿”是因为您使用秒作为依赖项。所以每次秒变化时,效果都必须再次运行,从而导致效果的销毁函数(您从效果返回的函数)被调用。
与其将秒作为依赖项,不如使用 setSeconds。
const [seconds, setSeconds] = React.useState(10);
useEffect(() => {
let didUnsub = false;
const id = setInterval(() => {
setSeconds((prev) => {
// while the count is greater than 0, continue to countdown
if (prev > 0) {
return prev - 1;
}
// once count eq 0, stop counting down
clearInterval(id);
didUnsub = true;
return 0;
});
}, 1000);
return () => {
console.log("unmounting");
// if the count didn't unsubscribe by reaching 0, clear the interval
if (!didUnsub) {
console.log("unsubscribing");
clearInterval(id);
}
};
}, [setSeconds]);
如果您查看下面的示例,您会看到效果仅在安装组件时运行一次。如果您要使组件卸载,则会调用destroy 函数。这是因为 setState 是一个调度函数,在渲染之间不会改变,因此不会导致效果被连续调用。
在示例中,您可以单击按钮在安装和拆卸计数器之间切换。当您卸载它时,请注意它会登录控制台。
示例:https ://codesandbox.io/s/gallant-silence-ui0pv?file=/src/Countdown.js
推荐阅读
- laravel-5.8 - 如何在 laravel 的 CategoryController 中销毁方法?
- javascript - 如何使用按钮在数组中的多个 div 之间切换?
- nginx - 如何使用 Nginx 入口自动创建子域
- laravel - laravel pusher webhook 总是由于超时而失败
- python - 打开最近保存的图像并显示它们 python opencv
- aws-lambda - 多重触发 AWS Lambda 或 Step Function
- javascript - 我不明白 javascript 中的这段代码
- java - 如何从 Mono 获取用户对象
没有在Java中阻止它? - gcc - 使用 gcc 编译会导致 Docker 构建失败
- docker - docker 和 docker-compose 节点 api:npm ERR!代码 EACCES