Javascript 在React with Hooks中实现倒计时

Javascript 在React with Hooks中实现倒计时,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我试图用react钩子在屏幕上渲染倒计时,但我不确定渲染它的最佳方式 我知道我应该使用useEffect来比较当前状态和以前的状态,但我认为我做得不对 我会感谢你的帮助 我尝试过几种不同的方法,没有一种是有效的,比如在每次更新时设置状态,但最终都会疯狂地闪烁 const Timer = ({ seconds }) => { const [timeLeft, setTimeLeft] = useState(''); const now = Date.now();

我试图用react钩子在屏幕上渲染倒计时,但我不确定渲染它的最佳方式

我知道我应该使用useEffect来比较当前状态和以前的状态,但我认为我做得不对

我会感谢你的帮助

我尝试过几种不同的方法,没有一种是有效的,比如在每次更新时设置状态,但最终都会疯狂地闪烁



const Timer = ({ seconds }) => {
    const [timeLeft, setTimeLeft] = useState('');

    const now = Date.now();
    const then = now + seconds * 1000;

    const countDown = setInterval(() => {
        const secondsLeft = Math.round((then - Date.now()) / 1000);
        if(secondsLeft <= 0) {
            clearInterval(countDown);
            console.log('done!');
            return;
        }
        displayTimeLeft(secondsLeft);
    }, 1000);

    const displayTimeLeft = seconds => {
        let minutesLeft = Math.floor(seconds/60) ;
        let secondsLeft = seconds % 60;
        minutesLeft = minutesLeft.toString().length === 1 ? "0" + minutesLeft : minutesLeft;
        secondsLeft = secondsLeft.toString().length === 1 ? "0" + secondsLeft : secondsLeft;
        return `${minutesLeft}:${secondsLeft}`;
    }

    useEffect(() => {
        setInterval(() => {
            setTimeLeft(displayTimeLeft(seconds));
        }, 1000);
    }, [seconds])


    return (
        <div><h1>{timeLeft}</h1></div>
    )
}

export default Timer;```

常量计时器=({seconds})=>{
const[timeLeft,setTimeLeft]=useState(“”);
const now=Date.now();
const then=现在+秒*1000;
常量倒计时=设置间隔(()=>{
const secondsLeft=Math.round((then-Date.now())/1000);
如果(第二次){
let minutesLeft=数学楼层(秒/60);
设secondsLeft=seconds%60;
minutesLeft=minutesLeft.toString().length==1?“0”+minutesLeft:minutesLeft;
secondsLeft=secondsLeft.toString().length==1?“0”+secondsLeft:secondsLeft;
返回`${minutesLeft}:${secondsLeft}`;
}
useffect(()=>{
设置间隔(()=>{
setTimeLeft(显示TimeLeft(秒));
}, 1000);
},[秒])
返回(
{timeLeft}
)
}
导出默认定时器```
常量计时器=({seconds})=>{
//使用秒道具初始化timeLeft
const[timeLeft,setTimeLeft]=使用状态(秒);
useffect(()=>{
//到达0时提前退出
如果(!timeLeft)返回;
//save intervalId可在以下情况下清除间隔:
//组件重新渲染
const intervalId=setInterval(()=>{
setTimeLeft(timeLeft-1);
}, 1000);
//在重新渲染时清除“间隔”,以避免内存泄漏
return()=>clearInterval(intervalId);
//将timeLeft添加为依赖项以重新运行效果
//当我们更新它的时候
},[timeLeft]);
返回(
{timeLeft}
);
};

挂钩和间隔的经典问题。查看并注意在拆卸时取消间隔是否在此处使用setTimer更有意义?@AmirShitrit您的意思是
setTimeout
?两者都是有效选项,但
setTimeout
假设在
setInterval
假设触发三次时触发该函数g每x个时间点启动一次函数。由于
useffect
的性质,我们需要在每次
timeLeft
更改时设置并清除计时器,我想它不会真正起到“真实”的作用
setInterval
在这种情况下,我可以看到您的
setTimeout
点。是的。我的意思是设置超时。谢谢!@AmirShitrit是的,我更喜欢setTimeout
const Timer = ({ seconds }) => {
  // initialize timeLeft with the seconds prop
  const [timeLeft, setTimeLeft] = useState(seconds);

  useEffect(() => {
    // exit early when we reach 0
    if (!timeLeft) return;

    // save intervalId to clear the interval when the
    // component re-renders
    const intervalId = setInterval(() => {
      setTimeLeft(timeLeft - 1);
    }, 1000);

    // clear interval on re-render to avoid memory leaks
    return () => clearInterval(intervalId);
    // add timeLeft as a dependency to re-rerun the effect
    // when we update it
  }, [timeLeft]);

  return (
    <div>
      <h1>{timeLeft}</h1>
    </div>
  );
};