【问题标题】:Countdown timer using React Hooks使用 React Hooks 的倒数计时器
【发布时间】:2020-09-29 07:25:28
【问题描述】:

所以计时器起作用了。如果我用特定的倒计时数字硬编码this.state,则一旦页面加载,计时器就会开始倒计时。我希望时钟在单击按钮时开始倒计时,并具有将statenull 更改为随机生成的数字的功能。我对 React 有点陌生。我知道useState() 只设置初始值,但如果我使用点击事件,如何重置useState()?我一直在尝试使用setCountdown(ranNum),但它使我的应用程序崩溃。我确信答案是显而易见的,但我只是没有找到它。

如果我没有提供足够的代码,请告诉我。我不想发布整个shebang。

这是我的代码:

import React, { useState, useEffect } from 'react';

export const Timer = ({ranNum, timerComplete}) => {
    const [ countDown, setCountdown ] = useState(ranNum)
    useEffect(() => {
        setTimeout(() => {
            countDown - 1 < 0 ? timerComplete() : setCountdown(countDown - 1)
        }, 1000)
    }, [countDown, timerComplete])
    return ( <p >Countdown: <span>{ countDown }</span> </p> )
}


  handleClick(){
    let newRanNum = Math.floor(Math.random() * 20);
    this.generateStateInputs(newRanNum)
    let current = this.state.currentImg;
    let next = ++current % images.length;
    this.setState({
      currentImg: next,
      ranNum: newRanNum
    })
  }

 <Timer ranNum={this.state.ranNum} timerComplete={() => this.handleComplete()} />
 <Button onClick={this.handleClick}  name='Generate Inputs' />
 <DisplayCount name='Word Count: ' count={this.state.ranNum} />

【问题讨论】:

    标签: javascript reactjs timer components react-hooks


    【解决方案1】:

    您应该将countDown 存储在父组件中并将其传递给子组件。在父组件中,你应该使用一个变量来触发何时启动Timer。 你可以试试这个:

    import React from "react";
    
    export default function Timer() {
      const [initialTime, setInitialTime] = React.useState(0);
      const [startTimer, setStartTimer] = React.useState(false);
    
      const handleOnClick = () => {
        setInitialTime(5);
        setStartTimer(true);
      };
    
      React.useEffect(() => {
        if (initialTime > 0) {
          setTimeout(() => {
            console.log("startTime, ", initialTime);
            setInitialTime(initialTime - 1);
          }, 1000);
        }
    
        if (initialTime === 0 && startTimer) {
          console.log("done");
          setStartTimer(false);
        }
      }, [initialTime, startTimer]);
    
      return (
        <div>
          <buttononClick={handleOnClick}>
            Start
          </button>
          <Timer initialTime={initialTime} />
        </div>
      );
    }
    
    const Timer = ({ initialTime }) => {
      return <div>CountDown: {initialTime}</div>;
    };

    【讨论】:

      【解决方案2】:

      useState 就像您说的那样设置初始值,但在您的情况下,我认为您不想将countDown 存储在Timer 中。原因是当您启动应用程序时ranNumundefined,并以未定义的形式传递给Timer。当Timer 挂载时,useEffect 将使用值undefined 触发,这是您不想要的,因为它会触发setTimeout。我相信您可以将countDown 存储在Timer 的父级中,当从父级单击按钮时启动超时并将countDown 值作为道具发送到Timer,这将使组件方式更容易理解。

      【讨论】:

        【解决方案3】:

        这是一个使用 hooks 和 setInterval 的简单实现

        import React, {useState, useEffect, useRef} from 'react'
        import './styles.css'
        
        const STATUS = {
          STARTED: 'Started',
          STOPPED: 'Stopped',
        }
        
        export default function CountdownApp() {
          const [secondsRemaining, setSecondsRemaining] = useState(getRandomNum())
          const [status, setStatus] = useState(STATUS.STOPPED)
        
          const handleStart = () => {
            setStatus(STATUS.STARTED)
          }
          const handleStop = () => {
            setStatus(STATUS.STOPPED)
          }
          const handleRandom = () => {
            setStatus(STATUS.STOPPED)
            setSecondsRemaining(getRandomNum())
          }
          useInterval(
            () => {
              if (secondsRemaining > 0) {
                setSecondsRemaining(secondsRemaining - 1)
              } else {
                setStatus(STATUS.STOPPED)
              }
            },
            status === STATUS.STARTED ? 1000 : null,
            // passing null stops the interval
          )
          return (
            <div className="App">
              <h1>React Countdown Demo</h1>
              <button onClick={handleStart} type="button">
                Start
              </button>
              <button onClick={handleStop} type="button">
                Stop
              </button>
              <button onClick={handleRandom} type="button">
                Random
              </button>
              <div style={{padding: 20}}>{secondsRemaining}</div>
              <div>Status: {status}</div>
            </div>
          )
        }
        
        function getRandomNum() {
          return Math.floor(Math.random() * 20)
        }
        
        // source: https://overreacted.io/making-setinterval-declarative-with-react-hooks/
        function useInterval(callback, delay) {
          const savedCallback = useRef()
        
          // Remember the latest callback.
          useEffect(() => {
            savedCallback.current = callback
          }, [callback])
        
          // Set up the interval.
          useEffect(() => {
            function tick() {
              savedCallback.current()
            }
            if (delay !== null) {
              let id = setInterval(tick, delay)
              return () => clearInterval(id)
            }
          }, [delay])
        }
        

        这里是代码沙盒演示的链接:https://codesandbox.io/s/react-countdown-demo-random-c9dm8?file=/src/App.js

        【讨论】:

          猜你喜欢
          • 2019-11-29
          • 2017-04-14
          • 1970-01-01
          • 2020-04-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多