Rerender React component when props change?

夙愿已清 提交于 2019-12-08 06:15:31

问题


I have a react component with a Mobx store that looks like this:

class Board extends Component {
  componentDidMount() {
    this.props.dataStore.getSinglePlayer(1)
    this.props.squareStore.getAllSquares()
  }

  componentWillReceiveProps(nextProps) {
    if (
      this.props.dataStore.currentPlayer !==
      this.nextProps.dataStore.currentPlayer
    ) {
      this.nextProps.dataStore.getSinglePlayer(1)
    }
  }

  randomNumber() {
    return Math.floor(Math.random() * 6) + 1
  }

  roll(playerId, playerPosition) {
    let dice1 = this.randomNumber()
    let dice2 = this.randomNumber()

    let totalRoll = dice1 + dice2
    let totalPosition = totalRoll + playerPosition
    this.props.dataStore.changeUserPosition(playerId, totalRoll)
    document.getElementById('dice').innerHTML =
      'You rolled ' + totalRoll + '!  You are now on ' + totalPosition
  }

  render() {
    var player = {
      name: '',
      id: '',
      position: 0
    }
    console.log(this.props.dataStore.currentPlayer)
    if (this.props.dataStore.currentPlayer) {
      var currentPlayer = this.props.dataStore.currentPlayer
      player = {
        name: currentPlayer.name,
        id: currentPlayer.id,
        position: currentPlayer.position
      }
    }
    if (this.props.squareStore.squares) {
      var squares = this.props.squareStore.squares.map((square, i) => {
        var movement

        if (i == player.position) {
          movement = **
        }
        return (
          <li key={i}>
            <span>
              {square.title}
              <br />
              {movement}
              {square.price}
            </span>
          </li>
        )
      })
    } else {
      squares = <h4>Squares being loaded...</h4>
    }

    return (
      <div>
        <h1>Player: {player.name}</h1>
        <h2>Roll Dice!</h2>
        <button onClick={() => this.roll(player.id, player.position)}>
          Roll
        </button>{' '}
        <h1 id="dice">{}</h1>
        <div className="board">
          <ul>{squares}</ul>
        </div>
      </div>
    )
  }
}

export default inject('dataStore', 'squareStore')(observer(Board))

When the button is clicked this.props.dataStore.currentPlayer.position updates with a new value. However this new value only shows up when the page is manually refreshed. Is there a way of telling the component that the value has changed and it should rerender automatically?


回答1:


React.Component Lifecycle => Updating

An update can be caused by changes to props or state.

That's mean if you would like to re-render your component, you need to:

  • update Component state by using this.setState({ }) method
  • or pass updated props to that component from parent
  • or if you are using Redux/MobX as the state manager, you need to update the store, so connected props will be updated and re-render would be triggered



回答2:


You should consider using state so you setState to re renders your component. I Would suggest to refactor your code , especially your render. I think your player should be the state as some params changes each click (current player id, name and position )..be aware not to directly set your state in render cause this may cause infinite loop and render should always remain pure method. So this need more serious refactor. Moreover, usually there is no need to use stateful component where you don't have state or even a constructor!

Anyway here we just setState the totalPosition and this MAY work for you, but you should consider to optimize your component .

class Board extends Component {
constructor(props){
 super(props);
 this.state = {
 totalPosition: null
 }
}
  componentDidMount() {
    this.props.dataStore.getSinglePlayer(1)
    this.props.squareStore.getAllSquares()
  }

  componentWillReceiveProps(nextProps) {
    if (
      this.props.dataStore.currentPlayer !==
      this.nextProps.dataStore.currentPlayer
    ) {
      this.nextProps.dataStore.getSinglePlayer(1)
    }
  }

  randomNumber() {
    return Math.floor(Math.random() * 6) + 1
  }

  roll(playerId, playerPosition) {
    let dice1 = this.randomNumber()
    let dice2 = this.randomNumber()
    let totalRoll = dice1 + dice2
    this.setState({
      totalPostion: totalRoll + playerPosition
    });
    let totalPosition = totalRoll + playerPosition
    this.props.dataStore.changeUserPosition(playerId, totalRoll)
    document.getElementById('dice').innerHTML =
      'You rolled ' + totalRoll + '!  You are now on ' + this.state.playerPostion
  }

  render() {
    var player = {
      name: '',
      id: '',
      position: 0
    }
    console.log(this.props.dataStore.currentPlayer)
    if (this.props.dataStore.currentPlayer) {
      var currentPlayer = this.props.dataStore.currentPlayer
      player = {
        name: currentPlayer.name,
        id: currentPlayer.id,
        position: currentPlayer.position
      }
    }
    if (this.props.squareStore.squares) {
      var squares = this.props.squareStore.squares.map((square, i) => {
        var movement

        if (i == player.position) {
          movement = **
        }
        return (
          <li key={i}>
            <span>
              {square.title}
              <br />
              {movement}
              {square.price}
            </span>
          </li>
        )
      })
    } else {
      squares = <h4>Squares being loaded...</h4>
    }

    return (
      <div>
        <h1>Player: {player.name}</h1>
        <h2>Roll Dice!</h2>
        <button onClick={() => this.roll(player.id, player.position)}>
          Roll
        </button>{' '}
        <h1 id="dice">{}</h1>
        <div className="board">
          <ul>{squares}</ul>
        </div>
      </div>
    )
  }
}

export default inject('dataStore', 'squareStore')(observer(Board))



回答3:


<button onClick={() => this.roll(player.id, player.position); this.forceUpdate()}>



回答4:


I believe that you are not quite setting this interaction up correctly. I've not used MobX, but the react way to do this would be to just change the props. If you had a wrapping component around this that was listening to changes on the store, and passing the data into Board, it would automatically update. I think this MobX connect package will be very useful for you.



来源:https://stackoverflow.com/questions/48607560/rerender-react-component-when-props-change

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!