Home > Enterprise >  Why doesn't this code using useState() work as intended?
Why doesn't this code using useState() work as intended?

Time:11-11

I'm referring to the snippet in useEffect in the for loop at the last line. After I ran the code once and I console.logged the grids state with the button I rendered I'd get an array with only the number 196.

import { useState, useEffect } from "react";

const Gameboard = () => {
  const [grids, setGrids] = useState([]);
  
  useEffect(() => {
    setGrids([]);
    for (let i = 0; i < 196; i  ) {
      const grid = i   1;
      setGrids([...grids, grid]);
    }
  }, [])

  return (
    <div className="game-board">
    <button onClick={() => console.log(grids)}>click</button>
      {grids.map(grid => (
        <div key={ grid }></div>
      ))}
    </div>
  );
}
 
export default Gameboard;

Now I know how to fix that:

import { useState, useEffect } from "react";

const Gameboard = () => {
  const [grids, setGrids] = useState([]);
  
  useEffect(() => {
    setGrids([]);
    for (let i = 0; i < 196; i  ) {
      const grid = i   1;
      setGrids(grids => [...grids, grid]);
    }
  }, [])
  
  return (
    <div className="game-board">
      {grids.map(grid => (
        <div key={ grid }></div>
      ))}
    </div>
  );
}
 
export default Gameboard;

So the latter one works. That's clear. But why is it? Can someone explain me how this:

setGrids([...grids, grid]);

and this:

setGrids(grids => [...grids, grid]);

works? And why do we get good results with the last one unlike with the other. Thanks in advance!

CodePudding user response:

Avoid using the state variable in the setter function. Common practice is to use a variable called prevState (or something else, but prevState is frequently used in this kind of situations).

setGrids(prevState => [...prevState, grid])

So your code will look like this:

useEffect(() => {
    // setGrids([]); // Don't need this because is already initialized to []
    for (let i = 0; i < 196; i  ) {
      const grid = i   1;
      setGrids(prevState => [...prevState, grid]);
    }
  }, [])

Or may be try this:

useEffect(() => {
    const temp = [];
    for (let i = 0; i < 196; i  ) {
      const grid = i   1;
      temp.push(grid);
    }
    setGrid(temp);
  }, [])

So you only set the state once at the end of the loop and avoid unnecessary re-renders. But that will depend on your use case.

CodePudding user response:

setGrids([...grids, grid]); this one has the value of state but it needs to be rerendered to get a new value of state

for example you called setGrids() with new value for the first time and the component is not rerendered yet so you value of grid is not changed yet but in this way setGrids(grids => [...grids, grid]); you are telling the setter function to use the value of grid even if it's not rerendered

  • Related