【问题标题】:clearInterval not clearing after setInterval parameter value is updated更新 setInterval 参数值后 clearInterval 不清除
【发布时间】:2019-09-10 13:45:38
【问题描述】:

在这个游戏中(从 Youtube 获得),蛇在吃东西时会长大,而且速度也会加快。在蛇至少吃一顿饭之前,一切都很好。此时暂停、播放按钮根本不起作用,新游戏按钮会重置蛇的位置和食物位置,但游戏不会停止,速度也不会重置。

我知道问题出在哪里(increaseSpeed()),但我不知道要解决它。如果我从这个函数中删除 setInterval 返回,游戏的每个部分都可以正常工作,除了速度永远不会改变

const getRandomCoordinates = () => {
  let min = 1
  let max = 98
  let x = Math.floor((Math.random()*(max-min+1)+min)/2)*2
  let y = Math.floor((Math.random()*(max-min+1)+min)/2)*2
  return [x,y]
}

const initialState = {
  direction: 'RIGHT',
  speed: 200,
  food: getRandomCoordinates(),
  snakeDots: [
    [0,0],
    [2,0]
  ],
  message: ""
}

// GAMEBOARD COMPONENT
class GameBoard extends Component {

  state = initialState

  componentDidMount() {
    document.onkeydown = this.onKeyDown
  }

  componentDidUpdate() {
    this.checkIfOutOfBorders()
    this.checkIfCollapsed()
    this.checkIfEat()
  }

  playButton = () => {
    clearInterval(this.intervalId)
    this.intervalId = setInterval(this.moveSnake, this.state.speed)
  }

  pauseButton = () => {
    clearInterval(this.intervalId)
  }

  newGameButton = () => {
    this.setState(initialState)
    clearInterval(this.intervalId)
  }


  onKeyDown = (e) => {
    e = e || window.event;
    switch(e.keyCode) {
      case 38:
        this.setState({ direction: 'UP'})
        break
      case 40:
        this.setState({ direction: 'DOWN'})
        break
      case 37:
        this.setState({ direction: 'LEFT'})
        break
      case 39:
        this.setState({ direction: 'RIGHT'})
        break
      default:
    }
  }

  moveSnake = () => {
    let dots = [...this.state.snakeDots]
    let head = dots[dots.length - 1]

    switch (this.state.direction) {
      case 'RIGHT':
        head = [head[0] + 2, head[1]]
        break
      case 'LEFT':
        head = [head[0] - 2, head[1]]
        break
      case 'UP':
        head = [head[0], head[1] - 2]
        break
      case 'DOWN':
        head = [head[0], head[1] + 2]
        break
      default:
    }
    dots.push(head)
    dots.shift()
    this.setState({
      snakeDots: dots
    })
  }

  checkIfOutOfBorders = () => {
    let head = this.state.snakeDots[this.state.snakeDots.length - 1]
    if (head[0] >= 100 || head[1] >= 100 || head[0] < 0 || head[1] < 0) {
      this.onGameOver()
    }
  }

  checkIfCollapsed = () => {
    let snake = [...this.state.snakeDots]
    let head = snake[this.state.snakeDots.length - 1]
    snake.pop()
    snake.forEach(dot => {
      if (head[0] === dot[0] && head[1] === dot[1]) {
        this.onGameOver()
      }
    })
  }

  checkIfEat = () => {
    let head = this.state.snakeDots[this.state.snakeDots.length - 1]
    let food = this.state.food
    if (head[0] === food[0] && head[1] === food[1]) {
      this.setState({
        food: getRandomCoordinates()
      })
      this.growSnake()
      this.increaseSpeed()
    }
  }

  growSnake = () => {
    let newSnake = [...this.state.snakeDots]
    newSnake.unshift([])
    this.setState({
      snakeDots: newSnake
    })
  }

  increaseSpeed = () =>  {
    let speed = this.state.speed
    if (this.state.speed > 10) {
      this.setState({
        speed: speed - 10
      })
    }
    setInterval(this.moveSnake, this.state.speed)
  }

  onGameOver = () => {
    // alert(`Game over! You're snake length is ${this.state.snakeDots.length}`)
    this.newGameButton()
    console.log('over')

  }

  render () {
    return (
      <div className="console-container">
        <div className="game-area">
          <Snake snakeDots={ this.state.snakeDots } />
          <Food food={ this.state.food } />
        </div>
        <ControlPanel
          playButton={this.playButton}
          pauseButton={this.pauseButton}
          newGameButton={this.newGameButton}
          scoreboardMessage={this.scoreboardMessage}
        />
      </div>
    )
  }
}

export default GameBoard

【问题讨论】:

    标签: reactjs setinterval clearinterval


    【解决方案1】:

    这行increaseSpeed方法有3个问题:

    setInterval(this.moveSnake, this.state.speed);

    1. 您没有保存新的区间 ID
    2. 您使用旧的状态值(因为setState 是异步的)
    3. 您没有清除上一个间隔

    这应该有效:

      increaseSpeed = () =>  {
        let speed = this.state.speed
        if (this.state.speed > 10) {
          speed -= 10;
          this.setState({
            speed
          })
        }
        clearInterval(this.intervalId);
        this.intervalId = setInterval(this.moveSnake, speed);
      }
    

    【讨论】:

    • 我试过了,还是一样。在此函数中使用 clearInterval 一切正常,但速度不会增加。如果我删除它,那么原来的问题就会像描述的那样回来
    • 顺便说一句,setInterval 我没有使用this.state.speed,你试过了吗?
    • 是的。我从字面上粘贴了您的代码。由于某种原因,一旦 setInterval 被此函数更新,它就无法清除
    • 我很抱歉。您的解决方案确实有效。与我所看到的相比,说话的声音增加得如此缓慢,以至于我没有注意到差异。谢谢!
    • 很高兴它有帮助。快乐编码
    猜你喜欢
    • 2016-03-14
    • 2021-12-15
    • 2012-05-13
    • 1970-01-01
    • 2020-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多