Javascript React 应用程序中的 setInterval

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36299174/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 18:53:53  来源:igfitidea点击:

setInterval in a React app

javascriptreactjssettimeoutstate

提问by Jose

I'm still fairly new at React, but I've been grinding along slowly and I've encountered something I'm stuck on.

我在 React 方面还是个新手,但我一直在慢慢磨合,并且遇到了一些我一直在坚持的事情。

I am trying to build a "timer" component in React, and to be honest I don't know if I'm doing this right (or efficiently). In my code below, I set the state to return an object { currentCount: 10 }and have been toying with componentDidMount, componentWillUnmount, and renderand I can only get the state to "count down" from 10 to 9.

我正在尝试在 React 中构建一个“计时器”组件,老实说我不知道​​我这样做是否正确(或有效)。在下面我的代码,我设置状态来返回一个对象{ currentCount: 10 },并已与玩弄componentDidMountcomponentWillUnmountrender我只能得到状态,以“倒计时”,从10到9。

Two-part question: What am I getting wrong? And, is there a more efficient way of going about using setTimeout (rather than using componentDidMount& componentWillUnmount)?

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

Thank you in advance.

先感谢您。

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;

回答by dotnetom

I see 4 issues with your code:

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

  • In your timer method you are always setting your current count to 10
  • You try to update the state in render method
  • You do not use setStatemethod to actually change the state
  • You are not storing your intervalId in the state
  • 在您的计时器方法中,您始终将当前计数设置为 10
  • 您尝试在渲染方法中更新状态
  • 您不使用setState方法来实际更改状态
  • 您没有在状态中存储您的 intervalId

Let's try to fix that:

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

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

This would result in a timer that decreases from 10 to -N. If you want timer that decreases to 0, you can use slightly modified version:

这将导致计时器从 10 减少到 -N。如果您希望计时器减少到 0,您可以使用稍微修改的版本:

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

回答by Greg Herbowicz

Updated 10-second countdown using class Clock extends Component

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

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;

回答by Greg Herbowicz

Updated 10-second countdown using Hooks(a new feature proposal that lets you use state and other React features without writing a class. They're currently in React v16.7.0-alpha).

使用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'));

回答by tulsluper

Thanks @dotnetom, @greg-herbowicz

谢谢@dotnetom,@greg-herbowicz

If it returns "this.state is undefined" - bind timer function:

如果它返回“this.state is undefined”——绑定定时器函数:

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

回答by Ashok Shah

Updating state every second in the react class. Note the my index.js passes a function that return current time.

在反应类中每秒更新状态。注意我的 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;

回答by Jo E.

If anyone is looking for a React Hook approach to implementing setInterval. Dan Abramov talked about it on his blog. Check it out if you want a good read about the subject including a Class approach. Basically the code is a custom Hook that turns setInterval as declarative.

如果有人正在寻找实现 setInterval 的 React Hook 方法。Dan Abramov 在他的博客上谈到了这件事。如果您想阅读有关该主题的好书,包括 Class 方法,请查看它。基本上,代码是一个自定义 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]);
}

Also posting the CodeSandbox link for convenience: https://codesandbox.io/s/105x531vkq

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