import React , {useState, useEffect} from 'react';
const Timer = () =>{
const [timer, setTimer] = useState(120);
const countTimer = () =>{
if(timer <= 0){
localStorage.clear("timer");
console.log("timer less then 0")
return;
} else {
console.log("greater then 0")
setTimer(timer -1) ;
localStorage.setItem("timer",timer);
setTimeout(countTimer(),1000);
}
}
useEffect(()=>{
if(localStorage.getItem("timer")){
setTimer(localStorage.getItem("timer"));
} else {
setTimer(120);
}
if(timer){
setTimeout(countTimer(),1000);
}
},[timer])
return (
<div align="center">
Timer :{timer}
</div>
)
}
export default Timer我的目标是在react中实现倒计时,它将与本地存储同步,并通过浏览器选项卡与显示计数器的页面同步,希望同步状态定时器和本地存储定时器,将它们放在定时器的useEffect中,更改状态更新定时器,并在setTimeout中更新本地存储。帮帮我,谢谢
发布于 2021-06-25 20:08:17
您的代码有一些问题。
第一个问题是setTimeout接受回调函数,这是它的第一个agrument。它将在作为第二个参数提供的时间之后执行。但是,不是将函数countTimer作为回调传递,而是传递它的执行结果。
if(timer){
setTimeout(countTimer(),1000); // here you're passing as the callback
// the result of execution of countTimer
// namely `undefined` value
}另一个问题是,您要给setTimeout打两次电话。在每次更改useEffect变量时将执行的timer钩子内部,以及每次执行时在countTimer函数中执行。
还有一个问题。每次timer变量发生变化时,您都会从localStorage读取timer键并再次设置setTimer。当state发生变化时,useEffect会引起对安排另一个渲染的反应。而您的代码将触发几乎无止境的循环。这将使组件不断更新,直到时间耗尽为止。
还有另一个问题。如果您的组件在超时仍然运行时被卸载。挂起的函数最终将被执行。它将向localStorage写入卸载前的timer值。如果您再次挂载此组件,则执行挂起超时时可能会覆盖新创建的值。
这是一个很好的习惯,以清除任何悬而未决的超时或其他影响的卸载。所以如果setTimeout还在运行的话,你最好还是清理它。为此,您必须将cleanup函数作为useEffect钩子的返回值返回。
总结如下:
setTimeout,而不是其执行的结果useEffect中触发无休止的重发器总之,应该是这样的:
import * as React from 'react'
const Timer = () => {
const initialTimer = localStorage.getItem("timer") ?? 120;
const timeoutId = React.useRef(null);
const [timer, setTimer] = React.useState(initialTimer);
const countTimer = React.useCallback(() => {
if (timer <= 0) {
localStorage.clear("timer");
} else {
setTimer(timer - 1);
localStorage.setItem("timer", timer);
}
}, [timer]);
React.useEffect(() => {
timeoutId.current = window.setTimeout(countTimer, 1000);
// cleanup function
return () => window.clearTimeout(timeoutId.current);
}, [timer, countTimer]);
return <div align="center">Timer :{timer}</div>;
}
export default Timerhttps://stackoverflow.com/questions/68134405
复制相似问题