Context: I am rendering a 2-dimensional grid, where each cell is a Node object with properties: row
, col
, isGood
. I create the grid and and initialize the initialGrid with a full grid.
Now I have onClick
action that changes the property of isGood
of clicked cell would change and it should render. However even if the change happens and the re-rendering does not happen.
Below is my code.
import { useState } from "react";
import "./App.css";
class Node {
constructor(x, y) {
this.row = x;
this.col = y;
this.isGood = false;
}
}
const totalRows = 5;
const totalCols = 5;
var grid = [];
const createNodes = () => {
grid = [];
for (let row = 0; row < totalRows; row) {
var newRow = [];
for (let col = 0; col < totalCols; col) {
newRow.push(new Node(row, col));
}
grid.push(newRow);
}
console.log(grid);
};
createNodes();
const App = () => {
const [initialGrid, setGrid] = useState(grid);
const handleClick = (rowIndex, colIndex) => {
initialGrid[rowIndex][colIndex].isGood = true;
setGrid(initialGrid);
};
const getNodeClass = (node) => {
const newClassName = node.isGood === true ? "node-good" : "node";
return newClassName;
};
return (
<div>
{initialGrid.map((row, rowIndex) => {
return (
<div key={rowIndex} className="rows">
{row.map((column, columnIndex) => {
return (
<div
className={getNodeClass(column)}
id={`${rowIndex}-${columnIndex}`}
key={columnIndex}
onClick={() => {
handleClick(rowIndex, columnIndex);
}}
></div>
);
})}
</div>
);
})}
</div>
);
};
export default App;
How can I re-render the grid ?
my onClick
works and I can see it on console.log
however the re-rendering doesnot happen even if I call setGrid
CodePudding user response:
You need to construct a new array in the call to setGrid or React won't realize it needs to re-render. You can do this with the spread operator, adding the individual elements of the old array to your new array:
const handleClick = (rowIndex, colIndex) => {
initialGrid[rowIndex][colIndex].isGood = true;
setGrid([...initialGrid]);
};
We're also told React works better if we make the call to setGrid into a function as below, which also works. Personally I'm not sure if this is strictly necessary in this example and the code is arguably less clear:
const handleClick = (rowIndex, colIndex) => {
initialGrid[rowIndex][colIndex].isGood = true;
setGrid((ary) => [...ary]);
};