Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/427.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React中的倒计时计时器_Javascript_Reactjs_Countdown - Fatal编程技术网

Javascript React中的倒计时计时器

Javascript React中的倒计时计时器,javascript,reactjs,countdown,Javascript,Reactjs,Countdown,我在JavaScript中见过很多倒计时程序,我想让其中一个在React中工作 我借用了我在网上找到的这个功能: secondsToTime(secs){ let hours = Math.floor(secs / (60 * 60)); let divisor_for_minutes = secs % (60 * 60); let minutes = Math.floor(divisor_for_minutes / 60); let divisor_for_

我在JavaScript中见过很多倒计时程序,我想让其中一个在React中工作

我借用了我在网上找到的这个功能:

secondsToTime(secs){
    let hours = Math.floor(secs / (60 * 60));

    let divisor_for_minutes = secs % (60 * 60);
    let minutes = Math.floor(divisor_for_minutes / 60);

    let divisor_for_seconds = divisor_for_minutes % 60;
    let seconds = Math.ceil(divisor_for_seconds);

    let obj = {
        "h": hours,
        "m": minutes,
        "s": seconds
    };
    return obj;
  };
然后我自己写了这段代码

  initiateTimer = () => {
    let timeLeftVar = this.secondsToTime(60);
    this.setState({ timeLeft: timeLeftVar })
  };

  startTimer = () => {
    let interval = setInterval(this.timer, 1000);
    this.setState({ interval: interval });
  };

  timer = () => {
    if (this.state.timeLeft >0){
      this.setState({ timeLeft: this.state.timeLeft -1 });
    }
    else {
      clearInterval(this.state.interval);
      //this.postToSlack();
    }
  };
当前单击一次,它会将屏幕上的时间设置为:
剩余时间:1米:0秒
但它并没有将其缩减为剩余时间:0 m:59 s,然后再缩减为剩余时间:0 m:58 s等

我想我需要用一个不同的参数再次调用这个函数。我该怎么做呢

编辑:我忘了说,我想要功能,以便我可以使用秒到分和秒

问题在于您的“this”值。 计时器函数无法访问“状态”属性,因为它在不同的上下文中运行。我建议你这样做:

...
startTimer = () => {
  let interval = setInterval(this.timer.bind(this), 1000);
  this.setState({ interval });
};
正如您所看到的,我在计时器函数中添加了一个“bind”方法。这允许计时器在调用时访问react组件的相同“This”(这是使用javascript时的主要问题/改进)

另一个选项是使用另一个箭头功能:

startTimer = () => {
  let interval = setInterval(() => this.timer(), 1000);
  this.setState({ interval });
};

您必须在剩余的秒数(每次调用间隔)内每隔一秒设置一次状态。下面是一个例子:

类示例扩展了React.Component{
构造函数(){
超级();
this.state={time:{},秒数:5};
这个计时器=0;
this.startTimer=this.startTimer.bind(this);
this.countDown=this.countDown.bind(this);
}
第二次(秒){
让小时数=数学楼层(秒/(60*60));
让除数为分钟=s%(60*60);
让分钟=数学地板(除数为分钟/60);
让除数为秒=除数为分钟%60;
设秒=Math.ceil(除数为秒);
设obj={
“h”:小时,
“m”:分钟,
“s”:秒
};
返回obj;
}
componentDidMount(){
让timeLeftVar=this.secondsToTime(this.state.seconds);
this.setState({time:timeLeftVar});
}
startTimer(){
如果(this.timer==0&&this.state.seconds>0){
this.timer=setInterval(this.countDown,1000);
}
}
倒计时{
//移除一秒钟,设置状态以便重新渲染。
设秒数=this.state.seconds-1;
这是我的国家({
时间:这个。秒到秒(秒),
秒:秒,
});
//检查我们是否在零位。
如果(秒==0){
clearInterval(这个计时器);
}
}
render(){
返回(
开始
m:{this.state.time.m}s:{this.state.time.s}
);
}
}
ReactDOM.render(,document.getElementById('View'))


setInterval的一个缺点是它会减慢主线程的速度。您可以使用
requestAnimationFrame
执行倒计时,以防止出现这种情况。例如,这是我的通用倒计时组件:

class Timer extends Component {
  constructor(props) {
    super(props)
    // here, getTimeRemaining is a helper function that returns an 
    // object with { total, seconds, minutes, hours, days }
    this.state = { timeLeft: getTimeRemaining(props.expiresAt) }
  }

  // Wait until the component has mounted to start the animation frame
  componentDidMount() {
    this.start()
  }

  // Clean up by cancelling any animation frame previously scheduled
  componentWillUnmount() {
    this.stop()
  }

  start = () => {
    this.frameId = requestAnimationFrame(this.tick)
  }

  tick = () => {
    const timeLeft = getTimeRemaining(this.props.expiresAt)
    if (timeLeft.total <= 0) {
      this.stop()
      // ...any other actions to do on expiration
    } else {
      this.setState(
        { timeLeft },
        () => this.frameId = requestAnimationFrame(this.tick)
      )
    }
  }

  stop = () => {
    cancelAnimationFrame(this.frameId)
  }

  render() {...}
}
类计时器扩展组件{
建造师(道具){
超级(道具)
//在这里,getTimeRemaining是一个帮助函数,它返回
//对象的{total,seconds,minutes,hours,days}
this.state={timeLeft:getTimeRemaining(props.expiresAt)}
}
//等待组件安装完毕,以启动动画帧
componentDidMount(){
这个。开始()
}
//通过取消先前计划的任何动画帧进行清理
组件将卸载(){
这个
}
开始=()=>{
this.frameId=requestAnimationFrame(this.tick)
}
勾号=()=>{
const timeLeft=getTimeRemaining(this.props.expiresAt)
if(timeLeft.total this.frameId=requestAnimationFrame(this.tick)
)
}
}
停止=()=>{
cancelAnimationFrame(此.frameId)
}
render(){…}
}
类示例扩展了React.Component{
构造函数(){
超级();
this.state={time:{},秒数:5};
这个计时器=0;
this.startTimer=this.startTimer.bind(this);
this.countDown=this.countDown.bind(this);
}
第二次(秒){
让小时数=数学楼层(秒/(60*60));
让除数为分钟=s%(60*60);
让分钟=数学地板(除数为分钟/60);
让除数为秒=除数为分钟%60;
设秒=Math.ceil(除数为秒);
设obj={
“h”:小时,
“m”:分钟,
“s”:秒
};
返回obj;
}
componentDidMount(){
让timeLeftVar=this.secondsToTime(this.state.seconds);
this.setState({time:timeLeftVar});
}
startTimer(){
如果(this.timer==0&&this.state.seconds>0){
this.timer=setInterval(this.countDown,1000);
}
}
倒计时{
//移除一秒钟,设置状态以便重新渲染。
设秒数=this.state.seconds-1;
这是我的国家({
时间:这个。秒到秒(秒),
秒:秒,
});
//检查我们是否在零位。
如果(秒==0){
clearInterval(这个计时器);
}
}
render(){
返回(
开始
m:{this.state.time.m}s:{this.state.time.s}
);
}
}
ReactDOM.render(,document.getElementById('View'))

这是一个使用钩子的解决方案,计时器组件,我正在用钩子复制上面相同的逻辑

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

const Timer = (props:any) => {
    const {initialMinute = 0,initialSeconds = 0} = props;
    const [ minutes, setMinutes ] = useState(initialMinute);
    const [seconds, setSeconds ] =  useState(initialSeconds);
    useEffect(()=>{
    let myInterval = setInterval(() => {
            if (seconds > 0) {
                setSeconds(seconds - 1);
            }
            if (seconds === 0) {
                if (minutes === 0) {
                    clearInterval(myInterval)
                } else {
                    setMinutes(minutes - 1);
                    setSeconds(59);
                }
            } 
        }, 1000)
        return ()=> {
            clearInterval(myInterval);
          };
    });

    return (
        <div>
        { minutes === 0 && seconds === 0
            ? null
            : <h1> {minutes}:{seconds < 10 ?  `0${seconds}` : seconds}</h1> 
        }
        </div>
    )
}

export default Timer;
从“React”导入React
从“react”导入{useState,useEffect};
常量计时器=(道具:任意)=>{
常量{initialMinute=0,initialSeconds=0}=props;
const[minutes,setMinutes]=使用状态(initialMinute);
const[seconds,setSeconds]=使用状态(initialSeconds);
useffect(()=>{
让myInterval=setInterval(()=>{
如果(秒>0){
设置秒(秒-1);
}
如果(秒===0){
如果(分钟===0){
清除间隔(myInterval)
}否则{
设置分钟数(分钟-1);
设置秒(59);
}
} 
}, 1000)
return()=>{
import React, { Component } from 'react';
import './App.css';

class App extends Component {
  constructor() {
    super();
    this.state = {
      hours: 0,
      minutes: 0,
      seconds:0
    }
    this.hoursInput = React.createRef();
    this.minutesInput= React.createRef();
    this.secondsInput = React.createRef();
  }

  inputHandler = (e) => {
    this.setState({[e.target.name]: e.target.value});
  }

  convertToSeconds = ( hours, minutes,seconds) => {
    return seconds + minutes * 60 + hours * 60 * 60;
  }

  startTimer = () => {
    this.timer = setInterval(this.countDown, 1000);
  }

  countDown = () => {
    const  { hours, minutes, seconds } = this.state;
    let c_seconds = this.convertToSeconds(hours, minutes, seconds);

    if(c_seconds) {

      // seconds change
      seconds ? this.setState({seconds: seconds-1}) : this.setState({seconds: 59});

      // minutes change
      if(c_seconds % 60 === 0 && minutes) {
        this.setState({minutes: minutes -1});
      }

      // when only hours entered
      if(!minutes && hours) {
        this.setState({minutes: 59});
      }

      // hours change
      if(c_seconds % 3600 === 0 && hours) {
        this.setState({hours: hours-1});
      }

    } else {
      clearInterval(this.timer);
    }
  }


  stopTimer = () => {
    clearInterval(this.timer);
  }

  resetTimer = () => {
    this.setState({
      hours: 0,
      minutes: 0,
      seconds: 0
    });
    this.hoursInput.current.value = 0;
    this.minutesInput.current.value = 0;
    this.secondsInput.current.value = 0;
  }


  render() {
    const { hours, minutes, seconds } = this.state;

    return (
      <div className="App">
         <h1 className="title"> (( React Countdown )) </h1>
         <div className="inputGroup">
            <h3>Hrs</h3>
            <input ref={this.hoursInput} type="number" placeholder={0}  name="hours"  onChange={this.inputHandler} />
            <h3>Min</h3>
            <input  ref={this.minutesInput} type="number"  placeholder={0}   name="minutes"  onChange={this.inputHandler} />
            <h3>Sec</h3>
            <input   ref={this.secondsInput} type="number"  placeholder={0}  name="seconds"  onChange={this.inputHandler} />
         </div>
         <div>
            <button onClick={this.startTimer} className="start">start</button>
            <button onClick={this.stopTimer}  className="stop">stop</button>
            <button onClick={this.resetTimer}  className="reset">reset</button>
         </div>
         <h1> Timer {hours}: {minutes} : {seconds} </h1>
      </div>

    );
  }
}

export default App;