让我们看看是否有人可以帮助我解决问题倒计时的问题。我正在尝试设置分钟和秒点击+和 - 然后将秒传递给一个名为tottime的新变量。然后,当用户点击Go!时,应该触发倒计时但是......它没有发生,我不知道为什么Chome不断冻结。
您可以在此处查看整个项目https://github.com/staranco/react-scoreboard
下面是代码:
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = {
secs: 0,
mins: 0,
tottime: 0
};
this.clickSum = this.clickSum.bind(this);
this.clickDif = this.clickDif.bind(this);
this.initCount = this.initCount.bind(this);
}
clickSum() {
if(this.state.secs < 59) {
this.setState({secs: this.state.secs + 1});
} else {
this.setState({secs: 0});
this.setState({mins: this.state.mins + 1});
}
this.setState({tottime: (this.state.secs + 1) + (this.state.mins * 60)});
console.log(this.state.tottime)
}
clickDif() {
if(this.state.secs > 0) {
this.setState({secs: this.state.secs - 1});
this.setState({tottime: (this.state.secs - 1) + (this.state.mins * 60)})
} else if(this.state.mins > 0 && this.state.secs <= 0) {
this.setState({mins: this.state.mins - 1});
this.setState({secs: 59});
}
}
initCount() {
var self = this;
while (self.state.tottime > 0) {
setInterval(function() {
console.log(self.state.tottime);
self.setState({tottime: self.state.tottime - 1})
}, 1000);
}
}
render() {
return (
<div className="timer">
<div className="timer_clock">
<span>{this.state.mins}</span>:<span>{this.state.secs}</span>
</div>
<div className="timer_countdown"><span>{this.state.tottime}</span></div>
<TimerBtn btnSymbol="+" onClick={this.clickSum} />
<TimerBtn btnSymbol="-" onClick={this.clickDif} />
<TimerBtn btnSymbol="Go!" onClick={this.initCount} />
</div>
);
}
};
答案 0 :(得分:1)
您的代码存在问题,
while(self.state.tottime > 0)
此条件始终为true
,浏览器将继续设置setIntervals
,并且不会执行setInterval
。
您可以按freeze chrome
按钮:)进行验证。您可以看到我添加的console.log
将被多次打印。
您可以将代码更改为这样的内容,
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = {
secs: 0,
mins: 0,
tottime: 0
};
this.clickSum = this.clickSum.bind(this);
this.clickDif = this.clickDif.bind(this);
this.initCount = this.initCount.bind(this);
this.initCountOld = this.initCountOld.bind(this);
}
clickSum() {
if(this.state.secs < 59) {
this.setState({secs: this.state.secs + 1});
} else {
this.setState({secs: 0});
this.setState({mins: this.state.mins + 1});
}
this.setState({tottime: (this.state.secs + 1) + (this.state.mins * 60)});
console.log(this.state.tottime)
}
clickDif() {
if(this.state.secs > 0) {
this.setState({secs: this.state.secs - 1});
this.setState({tottime: (this.state.secs - 1) + (this.state.mins * 60)})
} else if(this.state.mins > 0 && this.state.secs <= 0) {
this.setState({mins: this.state.mins - 1});
this.setState({secs: 59});
}
}
initCount() {
var self = this;
const refreshIntervalId = setInterval(()=>{
self.setState({
tottime: self.state.tottime - 1
})
if(this.state.tottime <= 0){ clearInterval(refreshIntervalId)}
}, 1000)
}
initCountOld() {
var self = this;
while (self.state.tottime > 0) {
console.log("setting infinite setintervals")
setInterval(function() {
console.log(self.state.tottime);
self.setState({tottime: self.state.tottime - 1})
}, 1000);
}
}
render() {
return (
<div className="timer">
<div className="timer_clock">
<span>{this.state.mins}</span>:<span>{this.state.secs}</span>
</div>
<div className="timer_countdown"><span>{this.state.tottime}</span></div>
<button btnSymbol="+" onClick={this.clickSum}>+</button>
<button btnSymbol="-" onClick={this.clickDif}>-</button>
<button btnSymbol="Go!" onClick={this.initCount}>Go</button>
<button onClick={this.initCountOld}>Freeze chrome</button>
</div>
);
}
};
ReactDOM.render(<Timer />,document.getElementById("app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
答案 1 :(得分:1)
问题在于您的initCount()
方法。
现在,你应该记住这个应用程序的两件事:
因此,为了解决上述问题2,您应该做的是:
while
循环setInterval()
内添加条件语句,这将确定您的倒计时是否必须停止或是否必须继续。如果必须停止,则应清除与倒计时相关的间隔现在如何清除间隔?继续阅读
setInterval()
会返回id
,您可以将其保存在某个变量中,然后您可以使用clearInterval()
并将id
传递给它以清除间隔。
例如:
var id = setInterval(foo, 1000);
clearInterval(id);
所以你的initCount()
必须是这样的(我已经注释掉了错误的代码):
initCount() {
var self = this;
//while (self.state.tottime > 0) {
self.intervalId = setInterval(function() {
console.log(self.state.tottime);
if(self.state.tottime > 0) {
// Decrease tottime if its not zero
self.setState({tottime: self.state.tottime - 1});
} else {
// Clear the timer if tottime == 0
clearInterval(self.intervalId);
}
}, 1000);
// }
}
以下是我使用您的github repo Countdown Sample
中的代码创建的示例希望有所帮助:)
答案 2 :(得分:0)
这里的问题是setState()
异步更新状态,这意味着您无法准确预测状态何时会更新。
查看setState的官方文档,here:
将
setState()
视为请求,而不是立即更新组件的命令。为了获得更好的感知性能,React可能会延迟它,然后在一次通过中更新几个组件。 React不保证立即应用状态更改。
setState()
并不总是立即更新组件。它可以批量推迟更新或推迟更新。这使得在调用setState()
潜在陷阱后立即阅读this.state。相反,请使用componentDidUpdate
或setState callback (setState(updater, callback))
,其中任何一个都可以保证在应用更新后触发。
因此,您的代码中发生的事情是您选择了tottime
的起始值,但是当您点击 Go!时,会发生以下情况:
self.state.tottime > 0
是真的。我们进入了while循环。self.state.tottime > 0
仍然是真的。要解决此问题,请尝试将initCount()
功能更改为:
initCount() {
var self = this;
this.interval = setInterval(function() {
self.setState({tottime: self.state.tottime - 1}, function() {
if(self.state.tottime == 0) {
clearInterval(this.interval);
this.interval = null;
}
})
}, 1000);
}
以下工作演示:
为了演示目的,我稍微简化了您的组件。
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = {
secs: 0,
mins: 0,
tottime: 10
};
this.initCount = this.initCount.bind(this);
}
initCount() {
var self = this;
this.interval = setInterval(function() {
self.setState({tottime: self.state.tottime - 1}, function() {
if(self.state.tottime == 0) {
clearInterval(this.interval);
this.interval = null;
}
})
}, 1000);
}
render() {
return (
<div className="timer">
<div className="timer_clock">
<span>{this.state.mins}</span>:<span>{this.state.secs}</span>
</div>
<div className="timer_countdown"><span>{this.state.tottime}</span></div>
<button onClick={this.initCount}>Go!</button>
</div>
);
}
}
ReactDOM.render(<Timer />, document.getElementById("myApp"));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="myApp"></div>
&#13;