简体   繁体   中英

correct way to bind an object as value of a component's state key in react

I'm creating a minesweeper React app and inside the Board stateful component I've initialized and populated the board with mines and other information.

The initialization of this board is made as follows

// Method that creates a board of empty tiles, populates it with mines and gets the number of neighbouring
// mines for every tile on the board. Returns the initialized board  
initializeBoard(height, width, mines){
    const emptyTiles = this.createEmptyArray(height, width);
    const populatedTiles = this.populateBoard(emptyTiles, height, width, mines);
    const neighbourTiles = this.getNumOfMinesNeighbours(populatedTiles,height, width);
    return this.renderBoard(neighbourTiles);
   }

renderBoard returns a JSX component.

I receive height, width and mines as props passed from another component.

My Board status looks like this:

state = {
    mineCount: this.props.mines,
    gameStatus: null,
    boardData: null
}

And I want to dynamically render the initialized board and update Board's state value for boardData key. Now, I've arrived two different approaches for this:

  1. dynamically call initialize board() in Board's render() method, and update its state somehow
  2. Directly assign the state boardData value with a call to initializeBoard()

Approach #1 would look like this, inside render():

render() {  
    const board= this.initializeBoard(this.props.height, this.props.width, this.props.mines);
    //Save state throws Maximum update depth exceeded.
    return (
        <div>
            {board}
        </div> ...} //end of render

Approach #2:

state = {
    mineCount: this.props.mines,
    gameStatus: null,
    boardData: this.initializeBoard(this.props.height, this.props.width, this.props.mineCount)
}

Now, I know that setting the state of the component inside render() is a no-no , but also I am unable to find a proper lifecycle hook that will work when an object is created prior to render() and then dynamically rendered into JSX, since I'm not receiving this object via props.

So What I want to know is this :

  • Is the approach #2 a good/appropriate one? Or is calling a method to store a state's key value a bad practice?
  • Is there something I'm missing when it comes to lifecycle hooks and objects created prior to render()?
  • Is there any 'best practice' to store a state's key value in this situation?

Is the approach #2 a good/appropriate one? Or is calling a method to store a state's key value a bad practice?

No, why should it?

Is there something I'm missing when it comes to lifecycle hooks and objects created prior to render()?

No. there is no valid reason to hook in there.

Is there any 'best practice' to store a state's key value in this situation?

yes, #2.

Maybe more comments in the code will help me to better understand the problem.

constructor(super) {
   state = {
     mineCount: this.props.mines,
     gameStatus: null,
     boardData: null
   }
   this.board = null
   this.populatedTiles = null;
   this.neighbourTiles = null; 
   this.width = this.props.width;
   this.height = this.props.height; 
}

componentDidMount() {
   this.initializeBoard(this.height, this.width, this.state.mines);
}

initializeBoard(height, width, mines){
   const emptyTiles = this.createEmptyArray(height, width);
   this.populatedTiles = this.populateBoard(emptyTiles, height, width, mines);
   this.neighbourTiles = this.getNumOfMinesNeighbours(populatedTiles,height, width);
}

render() {
   const board = this.renderBoard(this.neighbourTiles, this.state) || null;
   return (
     <div>
        {board}
     </div>
   )
} 

The previous poster answered your first two questions, I'll try to expand a little on the third.

The short answer is #2 is the better practice.

Try to think of this more as an Object Oriented Programming problem than a react problem. The react component you're referencing is just an instance of a react component class. Like any class, they have a constructor function. The idea is that you want to do any state initialization in the constructor. You want to have your "source of truth" ready to go when you first instantiate the class.

Therefore, it's a good idea to do your board initialization in the constructor when you first set state. This way, you avoid any inconsistencies in state between when you first instantiate the class and attempt to manipulate the board. It's also cleaner, easier to understand, and in line with typical OOP principles.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM