2

I'm learning react by making a battleship game. When the component loads, I create a new object (board) which I set as a state. Then I'd like to map the board itself, which is any array. However, react says cannot read property board of undefined. With console logging, I found out that at first when the page loads, playerBoard is an empty object, and only THEN sets it to the given object with setPlayerBoard. How could I avoid this?

App.js looks like this:

const GameControl = () => {
    const [playerBoard, setPlayerBoard] = useState({})
    
    //creating the board object when component mounts, setting it as a state
    useEffect(() => {
        const playerBoard = GameBoard('player');
        setPlayerBoard({...playerBoard});
    },[])

    return (
        <div className = 'board-container'>
            <div className = "board player-board">

            {   //mapping an array
                playerBoard.boardInfo.board.map((cell, i) => {
                    return (
                        <div className = {`cell player-cell`key = {i}></div>
                    )
                } )
            }
            </div>
       </div>
    )

}

1 Answer 1

4

If creating the game board is synchronous, then just use that as your default value for the state:

const [playerBoard, setPlayerBoard] = useState(GameBoard('player'));
// No use effect after this

If creating the gameboard is synchronous but expensive, you can instead pass a function into useState, and that function will only be called on the first render:

const [playerBoard, setPlayerBoard] = useState(() => GameBoard('player'));

If creating the game board is asynchronous, then you're right to use an effect, but there is no way to avoid the first render not having data. You will just need to make sure your component can work when it doesn't have data. A common way to do this is to start with the state being an value that indicates no data, and then check for it and return a placeholder. null's easier to check for than an empty object, so i'd recommend that:

const [playerBoard, setPlayerBoard] = useState(null);
    
useEffect(() => {
  // some asynchronous stuff, followed by a call to setPlayerBoard
},[])

if (!playerBoard) {
  return <div>Loading...</div>
  // Or if you don't want to show anything:
  // return null;
}

return (
  <div className='board-container'>
    // etc
  </div>
);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.