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
setInterval in a React app
提问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 render
and I can only get the state to "count down" from 10 to 9.
我正在尝试在 React 中构建一个“计时器”组件,老实说我不知道我这样做是否正确(或有效)。在下面我的代码,我设置状态来返回一个对象{ currentCount: 10 }
,并已与玩弄componentDidMount
,componentWillUnmount
和render
我只能得到状态,以“倒计时”,从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
setState
method 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