在 React 中的 clearInterval 之后重新启动 setInterval
Restarting setInterval after clearInterval in React
在我正在构建的这个游戏中,我在用户输了之后清除了 setInterval。当他们点击 Play Again 时?我希望计时器重新开始,但我在使用 React 时遇到了麻烦。我已经尝试了几种方法,比如将计时器分离到它自己的组件中,制作一个辅助函数,以及使用生命周期方法,但我似乎无法理解这一部分。我可以很好地启动和清除 setInterval,但它正在重新启动它,这是我的问题。
import React, {Component} from 'react';
// helper function to set a random action
function setRandomAction() {
let actions = ['bop it', 'pull it', 'twist it'];
let rando = actions[Math.floor(Math.random() * actions.length)];
return rando;
}
class BopIt extends Component {
constructor(props) {
super(props);
// set initial action in this.state so it is not empty on pageload
this.state = {
action: setRandomAction(),
countdown: 3,
userPressed: '',
play: true
}
this.bind = this.keyPressed.bind(this);
this.bind = this.keepPlaying.bind(this);
this.bind = this.timer.bind(this);
this.bind = this.startTimer.bind(this);
this.bind = this.endGame.bind(this);
this.quitGame = this.quitGame.bind(this);
this.playAgain = this.playAgain.bind(this);
}
componentDidMount() {
this.keyPressed();
this.startTimer();
}
startTimer() {
let setTimerTime = parseInt(`${this.state.countdown - 2}000`);
this.stopIntervalId = setInterval(() => this.timer(), setTimerTime);
}
componentWillUnmount() {
this.startTimer();
this.keyPressed();
this.keepPlaying();
this.endGame();
}
timer() {
var count = this.state.countdown;
if (count === 0) {
count = 4
}
this.setState({countdown: count - 1});
}
keyPressed() {
document.addEventListener('keyup', (e) => {
if (e.key === 'ArrowLeft') {
this.setState({
userPressed: 'pull it'
});
} else if (e.key === 'ArrowDown') {
this.setState({
userPressed: 'bop it'
});
} else if (e.key === 'ArrowRight') {
this.setState({
userPressed: 'twist it'
});
} else {
// this.endGame();
this.setState({
userPressed: 'wrong'
});
}
if (this.state.userPressed !== this.state.action) {
this.endGame();
} else {
this.keepPlaying();
}
});
}
keepPlaying() {
let actions = ['bop it', 'pull it', 'twist it'];
let rando = actions[Math.floor(Math.random() * actions.length)];
this.setState({
action: rando,
userPressed: ''
});
}
endGame() {
console.log('You Lost!!!');
this.setState({
play: false
});
}
quitGame() {
clearInterval(this.stopIntervalId);
}
playAgain() {
this.setState({
play: true,
action: setRandomAction(),
countdown: 3
});
}
render() {
// if (this.state.countdown <= 0) {
// this.endGame();
// }
console.log(this.state)
let gameAction = `${this.state.action} ${this.state.countdown}`;
return (
<div className="bop-it">
<div className="show-action">
{this.state.play ? gameAction : <ResetGame playAgain={this.playAgain} quitGame={this.quitGame}/> }
</div>
<span>Pull It</span>
<br/>
<span>Bop It</span>
<br/>
<span>Twist It</span>
</div>
);
}
}
class ResetGame extends Component {
render() {
return (
<div>
<input type="button" value="Play Again?" onClick={this.props.playAgain}/>
<input type="button" value="Quit Game?" onClick={this.props.quitGame}/>
</div>
);
}
}
export default BopIt
编辑:
我最终只是在 playAgain()
方法的末尾调用了 this.startTimer()
。我本可以发誓我以前做过,但显然没有。我还确保只在一个地方调用 clearInterval
,这样应用程序的其他部分就不会发生冲突。
我遇到的另一个问题是,每当我 setInterval
重新启动时,计时器都会以更快的速度倒计时。那是因为:
let setTimerTime = parseInt(`${this.state.countdown - 2}000`);
this.stopIntervalId = setInterval(() => this.timer(), setTimerTime);
我把那行代码放在那里是因为我最终希望用户选择游戏速度,但这完全弄乱了我应用程序状态对象中的 countdown
属性。暂时删除这条线也消除了一些混乱。
import React, {Component} from 'react';
// helper function to set a random action
function setRandomAction() {
let actions = ['bop it', 'pull it', 'twist it'];
let rando = actions[Math.floor(Math.random() * actions.length)];
return rando;
}
class BopIt extends Component {
constructor(props) {
super(props);
// set initial action in this.state so it is not empty on pageload
this.state = {
action: setRandomAction(),
countdown: 3,
userPressed: '',
play: true
}
this.bind = this.keyPressed.bind(this);
this.bind = this.keepPlaying.bind(this);
this.bind = this.endGame.bind(this);
this.bind = this.timer.bind(this);
this.bind = this.startTimer.bind(this);
this.quitGame = this.quitGame.bind(this);
this.playAgain = this.playAgain.bind(this);
}
componentDidMount() {
this.keyPressed();
this.startTimer();
}
startTimer() {
// let setTimerTime = parseInt(`${this.state.countdown - 2}000`);
this.stopIntervalId = setInterval(() => this.timer(), 1000);
}
componentWillUnmount() {
this.keyPressed();
this.keepPlaying();
this.endGame();
}
timer() {
let count = this.state.countdown;
if (count === 0) {
count = 4
// end the game if the timer hits 0
this.endGame();
}
this.setState({countdown: count - 1});
}
keyPressed() {
document.addEventListener('keyup', (e) => {
if (e.key === 'ArrowLeft') {
this.setState({
userPressed: 'pull it'
});
} else if (e.key === 'ArrowDown') {
this.setState({
userPressed: 'bop it'
});
} else if (e.key === 'ArrowRight') {
this.setState({
userPressed: 'twist it'
});
} else {
this.setState({
userPressed: 'wrong'
});
}
// if user presses wrong key, then the game is over
if (this.state.userPressed !== this.state.action) {
this.endGame();
} else {
// otherwise, reset the time and chooose a random action
this.keepPlaying();
}
});
}
keepPlaying() {
this.setState({
action: setRandomAction(),
countdown: 3,
userPressed: ''
});
}
endGame() {
console.log('You Lost!!!');
this.setState({
play: false
});
clearInterval(this.stopIntervalId);
}
quitGame() {
// clearInterval(this.stopIntervalId);
console.log('you have left the game')
}
playAgain() {
this.setState({
play: true,
action: setRandomAction(),
countdown: 3
});
this.startTimer();
}
render() {
let gameAction = `${this.state.action} ${this.state.countdown}`;
return (
<div className="bop-it">
<div className="show-action">
{this.state.play ? gameAction :
<ResetGame
playAgain={this.playAgain}
quitGame={this.quitGame}
/>
}
</div>
<span>Pull It</span>
<br/>
<span>Bop It</span>
<br/>
<span>Twist It</span>
</div>
);
}
}
class ResetGame extends Component {
render() {
return (
<div>
<input type="button" value="Play Again?" onClick={this.props.playAgain}/>
<input type="button" value="Quit Game?" onClick={this.props.quitGame}/>
</div>
);
}
}
export default BopIt
我认为问题可能是您同时设置了 2 个计时器,一个在 componentWillUnmount
中,另一个在 componentWillMount
中,当您删除它们时,您只删除了其中一个因为另一个被变量覆盖丢失了
我会在你的代码中更改以下方法,这样创建重复的计时器会更困难一些,这样它也会在再次播放后再次触发计时器
startTimer() {
let setTimerTime = parseInt(`${this.state.countdown - 2}000`);
if (!this.stopIntervalId) {
this.stopIntervalId = setInterval(() => this.timer(), setTimerTime);
}
}
quitGame() {
clearInterval(this.stopIntervalId);
this.stopIntervalId = undefined;
}
playAgain() {
this.setState({
play: true,
action: setRandomAction(),
countdown: 3
});
this.startTimer()
}
在我正在构建的这个游戏中,我在用户输了之后清除了 setInterval。当他们点击 Play Again 时?我希望计时器重新开始,但我在使用 React 时遇到了麻烦。我已经尝试了几种方法,比如将计时器分离到它自己的组件中,制作一个辅助函数,以及使用生命周期方法,但我似乎无法理解这一部分。我可以很好地启动和清除 setInterval,但它正在重新启动它,这是我的问题。
import React, {Component} from 'react';
// helper function to set a random action
function setRandomAction() {
let actions = ['bop it', 'pull it', 'twist it'];
let rando = actions[Math.floor(Math.random() * actions.length)];
return rando;
}
class BopIt extends Component {
constructor(props) {
super(props);
// set initial action in this.state so it is not empty on pageload
this.state = {
action: setRandomAction(),
countdown: 3,
userPressed: '',
play: true
}
this.bind = this.keyPressed.bind(this);
this.bind = this.keepPlaying.bind(this);
this.bind = this.timer.bind(this);
this.bind = this.startTimer.bind(this);
this.bind = this.endGame.bind(this);
this.quitGame = this.quitGame.bind(this);
this.playAgain = this.playAgain.bind(this);
}
componentDidMount() {
this.keyPressed();
this.startTimer();
}
startTimer() {
let setTimerTime = parseInt(`${this.state.countdown - 2}000`);
this.stopIntervalId = setInterval(() => this.timer(), setTimerTime);
}
componentWillUnmount() {
this.startTimer();
this.keyPressed();
this.keepPlaying();
this.endGame();
}
timer() {
var count = this.state.countdown;
if (count === 0) {
count = 4
}
this.setState({countdown: count - 1});
}
keyPressed() {
document.addEventListener('keyup', (e) => {
if (e.key === 'ArrowLeft') {
this.setState({
userPressed: 'pull it'
});
} else if (e.key === 'ArrowDown') {
this.setState({
userPressed: 'bop it'
});
} else if (e.key === 'ArrowRight') {
this.setState({
userPressed: 'twist it'
});
} else {
// this.endGame();
this.setState({
userPressed: 'wrong'
});
}
if (this.state.userPressed !== this.state.action) {
this.endGame();
} else {
this.keepPlaying();
}
});
}
keepPlaying() {
let actions = ['bop it', 'pull it', 'twist it'];
let rando = actions[Math.floor(Math.random() * actions.length)];
this.setState({
action: rando,
userPressed: ''
});
}
endGame() {
console.log('You Lost!!!');
this.setState({
play: false
});
}
quitGame() {
clearInterval(this.stopIntervalId);
}
playAgain() {
this.setState({
play: true,
action: setRandomAction(),
countdown: 3
});
}
render() {
// if (this.state.countdown <= 0) {
// this.endGame();
// }
console.log(this.state)
let gameAction = `${this.state.action} ${this.state.countdown}`;
return (
<div className="bop-it">
<div className="show-action">
{this.state.play ? gameAction : <ResetGame playAgain={this.playAgain} quitGame={this.quitGame}/> }
</div>
<span>Pull It</span>
<br/>
<span>Bop It</span>
<br/>
<span>Twist It</span>
</div>
);
}
}
class ResetGame extends Component {
render() {
return (
<div>
<input type="button" value="Play Again?" onClick={this.props.playAgain}/>
<input type="button" value="Quit Game?" onClick={this.props.quitGame}/>
</div>
);
}
}
export default BopIt
编辑:
我最终只是在 playAgain()
方法的末尾调用了 this.startTimer()
。我本可以发誓我以前做过,但显然没有。我还确保只在一个地方调用 clearInterval
,这样应用程序的其他部分就不会发生冲突。
我遇到的另一个问题是,每当我 setInterval
重新启动时,计时器都会以更快的速度倒计时。那是因为:
let setTimerTime = parseInt(`${this.state.countdown - 2}000`);
this.stopIntervalId = setInterval(() => this.timer(), setTimerTime);
我把那行代码放在那里是因为我最终希望用户选择游戏速度,但这完全弄乱了我应用程序状态对象中的 countdown
属性。暂时删除这条线也消除了一些混乱。
import React, {Component} from 'react';
// helper function to set a random action
function setRandomAction() {
let actions = ['bop it', 'pull it', 'twist it'];
let rando = actions[Math.floor(Math.random() * actions.length)];
return rando;
}
class BopIt extends Component {
constructor(props) {
super(props);
// set initial action in this.state so it is not empty on pageload
this.state = {
action: setRandomAction(),
countdown: 3,
userPressed: '',
play: true
}
this.bind = this.keyPressed.bind(this);
this.bind = this.keepPlaying.bind(this);
this.bind = this.endGame.bind(this);
this.bind = this.timer.bind(this);
this.bind = this.startTimer.bind(this);
this.quitGame = this.quitGame.bind(this);
this.playAgain = this.playAgain.bind(this);
}
componentDidMount() {
this.keyPressed();
this.startTimer();
}
startTimer() {
// let setTimerTime = parseInt(`${this.state.countdown - 2}000`);
this.stopIntervalId = setInterval(() => this.timer(), 1000);
}
componentWillUnmount() {
this.keyPressed();
this.keepPlaying();
this.endGame();
}
timer() {
let count = this.state.countdown;
if (count === 0) {
count = 4
// end the game if the timer hits 0
this.endGame();
}
this.setState({countdown: count - 1});
}
keyPressed() {
document.addEventListener('keyup', (e) => {
if (e.key === 'ArrowLeft') {
this.setState({
userPressed: 'pull it'
});
} else if (e.key === 'ArrowDown') {
this.setState({
userPressed: 'bop it'
});
} else if (e.key === 'ArrowRight') {
this.setState({
userPressed: 'twist it'
});
} else {
this.setState({
userPressed: 'wrong'
});
}
// if user presses wrong key, then the game is over
if (this.state.userPressed !== this.state.action) {
this.endGame();
} else {
// otherwise, reset the time and chooose a random action
this.keepPlaying();
}
});
}
keepPlaying() {
this.setState({
action: setRandomAction(),
countdown: 3,
userPressed: ''
});
}
endGame() {
console.log('You Lost!!!');
this.setState({
play: false
});
clearInterval(this.stopIntervalId);
}
quitGame() {
// clearInterval(this.stopIntervalId);
console.log('you have left the game')
}
playAgain() {
this.setState({
play: true,
action: setRandomAction(),
countdown: 3
});
this.startTimer();
}
render() {
let gameAction = `${this.state.action} ${this.state.countdown}`;
return (
<div className="bop-it">
<div className="show-action">
{this.state.play ? gameAction :
<ResetGame
playAgain={this.playAgain}
quitGame={this.quitGame}
/>
}
</div>
<span>Pull It</span>
<br/>
<span>Bop It</span>
<br/>
<span>Twist It</span>
</div>
);
}
}
class ResetGame extends Component {
render() {
return (
<div>
<input type="button" value="Play Again?" onClick={this.props.playAgain}/>
<input type="button" value="Quit Game?" onClick={this.props.quitGame}/>
</div>
);
}
}
export default BopIt
我认为问题可能是您同时设置了 2 个计时器,一个在 componentWillUnmount
中,另一个在 componentWillMount
中,当您删除它们时,您只删除了其中一个因为另一个被变量覆盖丢失了
我会在你的代码中更改以下方法,这样创建重复的计时器会更困难一些,这样它也会在再次播放后再次触发计时器
startTimer() {
let setTimerTime = parseInt(`${this.state.countdown - 2}000`);
if (!this.stopIntervalId) {
this.stopIntervalId = setInterval(() => this.timer(), setTimerTime);
}
}
quitGame() {
clearInterval(this.stopIntervalId);
this.stopIntervalId = undefined;
}
playAgain() {
this.setState({
play: true,
action: setRandomAction(),
countdown: 3
});
this.startTimer()
}