Перезапуск setInterval после clearInterval в React - PullRequest
0 голосов
/ 08 сентября 2018

В этой игре я строю, я очищаю setInterval после того, как пользователь проигрывает. Когда они нажимают «Воспроизвести снова»? Я хочу, чтобы таймер снова запустился, но у меня возникают проблемы с выполнением этого при использовании 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

EDIT:

В итоге я просто позвонил this.startTimer() в конце метода playAgain(). Я мог бы поклясться, что делал это раньше, но, очевидно, нет Я также проверяю, чтобы звонить 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

1 Ответ

0 голосов
/ 09 сентября 2018

Я думаю, что проблема может заключаться в том, что вы устанавливаете 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()
}
...