React.js - 如何停止 setInterval 并在点击后恢复

React.js - How to stop setInterval and resume it after click

我正在使用 React.js 开发 Game of Life。到目前为止一切正常,但我想添加额外的功能,允许停止游戏(循环)并在需要时恢复游戏。我不知道我该怎么做。所以在 main class 里面,我有一个方法/函数可以启动游戏,它是在单击 render():

中定义的按钮后触发的
  constructor(props) {
    super(props);
    this.state = {cellStates: Array(TOTAL_FIELDS).fill(0), cellID: Array(TOTAL_FIELDS), gameRunning: false, counter: 0}; //set and fill initial states

    this.changeState = this.changeState.bind(this);

    this.resetGame = this.resetGame.bind(this);
    this.startGame = this.startGame.bind(this);
    this.stopGame = this.stopGame.bind(this);
    this.showGameStatus = this.showGameStatus.bind(this);

    for (let o = 1; o <= TOTAL_FIELDS; o++)
    {
      this.state.cellID[o-1] = o;
    }
  }

startGame() {
    function checkZeros(arr) { //check if board is blank
      return arr === 0;
    }

    if (!this.state.cellStates.every(checkZeros)) {
      alert ('Game starts!');
      let cycle = this.state.counter; //define number of life cycle

      this.setState(() => {
        return {
          gameRunning: true //game is on
        };
      });

      $('#reset-button').attr("disabled", "disabled");
      $('#start-button').attr("disabled", "disabled");
      $('#stop-button').removeAttr("disabled"); //handle buttons


      let goGame = setInterval(() => {
        const newStates = [];

        for (let x = 0; x < TOTAL_FIELDS; x++) {
          if (this.state.cellStates[x] === 0) {  //cell is dead
            if (this.calculateCellsAround(x) === 3)
            {
              newStates.push(1);
            }
            else {
              newStates.push(this.state.cellStates[x]);
            }
          }
          else {  //cell is alive
            if (this.calculateCellsAround(x) === 3 || this.calculateCellsAround(x) === 2)
            {
              newStates.push(this.state.cellStates[x]);
            }
            else {
              newStates.push(0);
            }
          }
        }
        this.setState(() => {
            return {cellStates: newStates, counter: cycle++};
        });
      }, 50);
    }
    else {
      alert ("Please fill at least one cell to launch a game.")
    }
  }

  render() {
    return (
      <div style={{marginTop:0+"px"}} key="wrap-it-all">
        <Header />
        <Grid>
          <Row>
            <Col md={12}>
              <div className="board-outline">
                {this.createMap(140, TOTAL_FIELDS)}
              </div>
            </Col>
          </Row>
          <Row>
            <Col md={12}>
              <button id="start-button" onClick={() => this.startGame()}>Start</button>
              <button id="stop-button" onClick={() => this.stopGame()}>Stop</button>
              <button id="reset-button" onClick={() => this.resetGame()}>Reset</button>
              <p style={{color:`#fff`}}>Lifecycle: <span className="lifecycle">{this.state.counter}</span>. Game is <span className="gamerun">{this.showGameStatus()}</span>.</p>
              <Alert className="disclaimer" bsStyle="warning">
                <strong>Instruction:</strong> Select the initial state of cells and press the [Start] button.
              </Alert>
            </Col>
          </Row>
        </Grid>
      </div>
    );
  }

我认为这一切都与 mount/unmount 内置函数有关,但我不知道如何使用它们才能使其正常工作。

您需要使用 clearInterval(handle) on stop 取消间隔。 如果您想继续,只需再次使用 setInterval(callback, tick)

此外,只需将您的匿名函数(又名setInterval(() => {...})更改为

function onTimerTick() {
   //copy everything marked as "..." here
}

并使用 setInterval(onTimerTick, 50).

可以尝试把局部变量(let goGame)改成全局变量(this._timer),然后通过clearInterval(this._timer)

取消间隔

你可以这样做

  let intervalHandle: NodeJS.Timeout = null;

  const startIntervalTask = () => {
    intervalHandle = setInterval(() => {
      // execute this code after every 5000 miliseconds

    }, 5000);
  };

  const stopIntervalTask = ()=>{
    clearInterval(intervalHandle);    
  }