I have a div element with OnMouseEnter()
that changes its class and a OnMouseLeave()
that reverts its class, the onMouseLeave()
only works after the mouse pointer leaves the parent div of the element.
Working example here - https://codesandbox.io/s/old-violet-7ipbvb?file=/src/Grid.jsx&resolutionWidth=320&resolutionHeight=675
More details - Basically I have a parent div (called canvas) that has child divs (cells) inside to represent a matrix, the child divs change color on mouse enter and revert to original color on mouseleave, the problem is that cells change color on mouse enter but only revert the color when the pointer leave their parent div.
const [canvas, setcanvas] = useState([[]]);
const handleenter1 = (row, col) => {
const a = []
for (var i = 0; i<50; i++){
a.push([]);
for (var j=0; j<20; j++){
if (i=== row && j === col){
var obj = {x: i, y: j, status: "wall"};
a[i].push(obj);
}
else {
obj = canvas[i][j];
a[i].push(obj);
}
}
}
setcanvas(a);
}
const handleleave1 = (row, col ) => {}
const create = () => {
let a = [];
for (var i = 0; i<50; i++){
a.push([]);
for (var j=0; j<20; j++){
if (i === 10 && j === 10){
var obj = {x: i, y: j, status: "starter"};
a[i].push(obj);
}
else {
obj = {x: i, y: j, status: "space"};
a[i].push(obj);
}
}
}
setcanvas(a);
}
useEffect(create, []);
const m = canvas.map((objlist,index1)=> {
return (objlist.map((obj,index) => {
return (
<div key = {`${index1} ${index}`}
onMouseEnter ={()=> {handleenter1(obj.x,obj.y)}}
onMouseLeave = {()=> { handleleave1(obj.x ,obj.y) }}>
</div>);
}));
});
The issue is a race-condition between your handleentter1
and handleleave1
functions where mouseleave does not see the updated canvas
in time, which is why it mistakenly keeps the previous cell black.
If you refactor the functions to imperatively update the canvas state's status for the known row/column, you won't run into this issue. Now the setcanvas
does not collide since it's just setting the one cell it cares about and not all the other cells.
Here's a working sandbox:
const handleenter1 = (row, col) => {
setcanvas((c) => {
const p = [...c];
p[row][col].status = "wall";
return p;
});
};
const handleleave1 = (row, col) => {
setcanvas((c) => {
const p = [...c];
p[row][col].status = "space";
return p;
});
};