Search code examples
javascriptreactjsreact-hooksuse-state

How to update an index inside an array with hooks without hitting "Error: Too many re-renders."


I have an array of cells that I need to update based on some user input from a socket server. But whenever I try to update an index using useState(), react complains about "Error: Too many re-renders.". I tried adding a state to indicate that the grid has changed, but that still produces the same error. Please help me :<

const GameUI = ({ height, width }) => {
  const [grid, setGrid] = React.useState([]);
  const [didUpdate, setDidUpdate] = React.useState(0);

  React.useEffect(() => {
    for (let index = 0; index < 64; index++) {
      const gridItem = <GridSquare key={`${index}`} color="" />;
      setGrid((oldArray) => [...oldArray, gridItem]);
    }
  }, []);

  //not re-rendering the modified component
  const handleChange = () => {
    let board = [...grid]
    board[1] = <GridSquare key={`${0}${1}`} color="1" />;
    setGrid(board)
    // let count = didUpdate;
    // count += 1
    // setDidUpdate(count)
  };

  // handleChange();

  return (
    <div className="App">
      <GridBoard grid={grid} />
      <ScoreBoard />
      <Players />
      {handleChange()}
      {/* <MessagePopup /> */}
    </div>
  );
};

the grid

the errors


Solution

  • Every time you change a state provided from the useState hook, it re-renders your component. You are calling handleChange on every render, which is calling your setGrid state hook. Therefore, you are rendering your component infinitely.

    When do you actually need to call handleChange? Every animation frame? Every action event of some kind? Create an appropriate useEffect or useCallback hook (that includes used dependencies [array] as the second parameter), apply the appropriate event to your method and trigger it accordingly. If you go with a useEffect, don't forget to return a function that disables the event handling when the component is eventually unmounted or else you will have duplicate events triggering every time it gets remounted in the same application.