I understand that useState is asynchronous. Please read the full question before answering.
I'm trying to modify an element in an array with useState
but it doesn't work as expected.
The array and the function to modify it:
const [table, setTable] = useState(['blue', 'blue', 'blue', 'blue', 'blue']);
let currentShapePosition = 2;
function printTable() {
let newTable = [...table];
// let newTable = table;
newTable[currentShapePosition] = 'red';
setTable(newTable);
console.log('printTable newTable', newTable); // <-- the result is as expected
// log => printTable newTable ["blue", "blue", "red", "blue", "blue"]
console.log('printTable table', table); // <--- The problem is here. I don't get why the array never update
// log => printTable newTable ["blue", "blue", "blue", "blue", "blue"]
}
Because useState
is asynchronous, I understand that the array may not change immediately, but, inside the printTable
function the console.log
result is the same even after several re-renders.
When instead of:
let newTable = [...table]
I do this : let newTable = table
Then the state is updated inside the console.log generated in the function but then there is no re-rendering/component update.
I would like to understand why in the first case newTable = [...table]
inside the function the console.log result is the same after several re-renders.
And why in the second case newTable = table
there is no re-rendering of the component despite setTable(newTable)
.
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import "./style.css";
const App = () => {
let currentShapePosition = 2;
const [table, setTable] = useState(["blue", "blue", "blue", "blue", "blue"]);
useEffect(() => {
printTable();
window.addEventListener("keydown", handleKeyPress);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
console.log("render", table);
});
function printTable() {
let newTable = [...table];
// let newTable = table;
newTable[currentShapePosition] = "red";
setTable(newTable);
console.log("printTable newTable", newTable); // <-- the result is as expected
console.log("printTable table", table); // <--- The problem is here. I don't get why the initial value never change
}
function handleKeyPress(event) {
switch (event.key) {
case "Left": // IE/Edge specific value
case "ArrowLeft":
moveShape(-1);
break;
case "Right": // IE/Edge specific value
case "ArrowRight":
moveShape(1);
break;
default:
return;
}
}
function moveShape(direction) {
currentShapePosition += direction;
printTable();
}
return (
<table className="tetris-table">
<tbody>
<tr>
<td className={table[0]} />
<td className={table[1]} />
<td className={table[2]} />
<td className={table[3]} />
<td className={table[4]} />
</tr>
</tbody>
</table>
);
};
const root = document.getElementById("root");
ReactDOM.render(<App />, root);