React应用程序中的setInterval

setInterval in a React app

本文关键字:setInterval 应用程序 React      更新时间:2023-09-26

我在React还是个新手,但我一直在慢慢地努力,遇到了一些问题。

我正试图在React中构建一个"定时器"组件,老实说,我不知道我做得是否正确(或有效)。在下面的代码中,我将状态设置为返回对象{ currentCount: 10 },并且一直在玩componentDidMountcomponentWillUnmountrender,我只能将状态从10"倒计时"到9。

由两部分组成的问题:我做错了什么?还有,有没有更有效的方法来使用setTimeout(而不是使用componentDidMount&componentWillUnmount)?

提前谢谢。

import React from 'react';
var Clock = React.createClass({
  getInitialState: function() {
    return { currentCount: 10 };
  },
  componentDidMount: function() {
    this.countdown = setInterval(this.timer, 1000);
  },
  componentWillUnmount: function() {
    clearInterval(this.countdown);
  },
  timer: function() {
    this.setState({ currentCount: 10 });
  },
  render: function() {
    var displayCount = this.state.currentCount--;
    return (
      <section>
        {displayCount}
      </section>
    );
  }
});
module.exports = Clock;

我看到您的代码有4个问题:

  • 在计时器方法中,您总是将当前计数设置为10
  • 尝试在渲染方法中更新状态
  • 您没有使用setState方法来实际更改状态
  • 您没有将intervalId存储在该州

让我们试着解决这个问题:

componentDidMount: function() {
   var intervalId = setInterval(this.timer, 1000);
   // store intervalId in the state so it can be accessed later:
   this.setState({intervalId: intervalId});
},
componentWillUnmount: function() {
   // use intervalId from the state to clear the interval
   clearInterval(this.state.intervalId);
},
timer: function() {
   // setState method is used to update the state
   this.setState({ currentCount: this.state.currentCount -1 });
},
render: function() {
    // You do not need to decrease the value here
    return (
      <section>
       {this.state.currentCount}
      </section>
    );
}

这将导致计时器从10减少到-N。如果你想要定时器减少到0,你可以使用稍微修改过的版本:

timer: function() {
   var newCount = this.state.currentCount - 1;
   if(newCount >= 0) { 
       this.setState({ currentCount: newCount });
   } else {
       clearInterval(this.state.intervalId);
   }
},

使用class Clock extends Component 更新了10秒倒计时

import React, { Component } from 'react';
class Clock extends Component {
  constructor(props){
    super(props);
    this.state = {currentCount: 10}
  }
  timer() {
    this.setState({
      currentCount: this.state.currentCount - 1
    })
    if(this.state.currentCount < 1) { 
      clearInterval(this.intervalId);
    }
  }
  componentDidMount() {
    this.intervalId = setInterval(this.timer.bind(this), 1000);
  }
  componentWillUnmount(){
    clearInterval(this.intervalId);
  }
  render() {
    return(
      <div>{this.state.currentCount}</div>
    );
  }
}
module.exports = Clock;

使用Hooks更新了10秒倒计时(一个新的功能提案,允许您在不编写类的情况下使用状态和其他React功能。它们目前在React v16.7.0-alpha中)。

import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
const Clock = () => {
    const [currentCount, setCount] = useState(10);
    const timer = () => setCount(currentCount - 1);
    useEffect(
        () => {
            if (currentCount <= 0) {
                return;
            }
            const id = setInterval(timer, 1000);
            return () => clearInterval(id);
        },
        [currentCount]
    );
    return <div>{currentCount}</div>;
};
const App = () => <Clock />;
ReactDOM.render(<App />, document.getElementById('root'));

如果有人正在寻找React Hook方法来实现setInterval。丹·阿布拉莫夫在他的博客上谈到了这件事。如果你想好好读一读这门课,包括课堂教学法,可以看看它。基本上,代码是一个自定义Hook,它将setInterval转换为声明性的。

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]);
}

为了方便起见,还发布了CodeSandbox链接:https://codesandbox.io/s/105x531vkq

使用React挂钩管理setInterval:

  const [seconds, setSeconds] = useState(0)
  const interval = useRef(null)
  useEffect(() => { if (seconds === 60) stopCounter() }, [seconds])
  const startCounter = () => interval.current = setInterval(() => {
    setSeconds(prevState => prevState + 1)
  }, 1000)
  const stopCounter = () => clearInterval(interval.current)

感谢@dotnetom,@greg herbowicz

如果返回"this.state is undefined"-绑定计时器函数:

constructor(props){
    super(props);
    this.state = {currentCount: 10}
    this.timer = this.timer.bind(this)
}

如果您使用Dan AbramovuseInterval钩子,并且想要手动取消当前时间间隔,则只需要再次调用钩子,将null作为delay变量。

你可以在这里查看一个工作示例https://codesandbox.io/s/useinterval-cancel-interval-dan-abramov-extended-oe45z?file=/src/index.js

简单的做法是将其添加到窗口变量中。

useEffect(() => {
    window.interval23 = setInterval(
      () => setState('something'),
      2500
    )
    return () => {
      clearInterval(window.interval23)
    }
 }, [])

但是,请确保使用窗口变量创建的任何内容都尽可能保持其唯一性,因为如果该变量已经存在,则该窗口变量可能会在库中中断。

您可以使用interval来设置状态,方法是通过组合setTimeout和useEffect 创建我称之为假递归的递归

  import {useEffect,useState} from 'react'
  const [state,setState]=useState(0)
  function Interval(){
      setTimeout(()=>{
         setState(state+1)
       },2000)
  }
   useEffect(()=>Interval(),[state])
 //this code runs repeatedly in interval of 2 seconds

在react类中每秒更新一次状态。请注意,我的index.js传递了一个返回当前时间的函数。

import React from "react";
class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      time: this.props.time,
    }        
  }
  updateMe() {
    setInterval(()=>{this.setState({time:this.state.time})},1000)        
  }
  render(){
  return (
    <div className="container">
      <h1>{this.state.time()}</h1>
      <button onClick={() => this.updateMe()}>Get Time</button>
    </div>
  );
}
}
export default App;
import React, { useState, useEffect } from "react";
export const Count = () => {
const [currentCount, setCount] = useState(1);
const timer = () => setCount(currentCount + 1);
useEffect(
    () => {
        if (currentCount <= 0) {
            return;
        }
        const id = setInterval(timer, 1000);
        return () => clearInterval(id);
    },
    [currentCount]
);
console.log(currentCount)
return <div>Count : - {currentCount}</div>;
};