In this codesandbox I am trying to change the background color of a div element on mouseenter and revert it on mouse leave. It only works on the outermost edge divs.
I know that setting state is "async" but the fact it does work on the outer edge makes me question it being a closure issue.
Using onMouseOut does not make a difference. I could be approaching a problem like this the wrong way completely but I cannot figure out what is wrong with the current implementation.
You need to update the state bases on previous value. That's a closure issue. You don't need to use the editGrid
state. Instead use setEditGrid with produce function which will pass previous value as first argument.
setEditGrid(
produce((draft) => {
draft[rowIndex][colIndex] = 2;
})
);
You can just update changes in that argument (Mostly we call it as draft). You can read more passing a function in setState in React Docs
You can improve one thing in your code. You don't need to set id
to each grid block. Instead use the rowIndex
and colIndex
if there's no such requirement that affects the grid structure.
import { useState, Fragment } from "react";
import produce from "immer";
const colors = ["", "#A5668B", "#FACFAD", "#F8BD7F", "#7DAF9C", "#95190C"];
export default function App() {
const [editGrid, setEditGrid] = useState([
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
]);
// const [currentShip, setCurrentShip] = useState(2);
return (
<div className='App'>
<div style={{ display: "grid", textAlign: "center", gridTemplateColumns: "repeat(11, minmax(10px, 50px))" }}>
{["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"].map((letter) => {
return (
<div key={letter} className='p-4'>
{letter}
</div>
);
})}
{editGrid.map((rows, rowIndex) =>
rows.map((col, colIndex) => {
return (
<Fragment key={`${rowIndex}-${colIndex}`}>
{colIndex === 0 && <div>{rowIndex + 1}</div>}
<div
style={{ backgroundColor: colors[editGrid[rowIndex][colIndex]], aspectRatio: 1 / 1 }}
onMouseOver={(e) => {
setEditGrid(
produce((draft) => {
draft[rowIndex][colIndex] = 2;
})
);
}}
onMouseOut={(e) => {
setEditGrid(
produce((draft) => {
draft[rowIndex][colIndex] = 0;
})
);
}}
>
{editGrid[rowIndex][colIndex]}
</div>
</Fragment>
);
})
)}
</div>
</div>
);
}