I'm trying to capture mouseover events for fabric object added some time after the canvas was initialized. I'm using react, so I'm doing that in a useEffect
hook.
useEffect(() => {
canvasRef.current = new fabric.Canvas("c", {
width: 300,
height: 600,
backgroundColor: "#666",
selection: false
});
canvasRef.current.add(
new fabric.Rect({
width: 100,
height: 100,
top: 100,
left: 100,
fill: "#660000"
})
);
canvasRef.current.on("mouse:over", function (e) {
console.log("mouse over", e.e.clientX, e.e.clientY, e.target);
});
canvasRef.current.requestRenderAll();
setTimeout(() => {
canvasRef.current.add(
new fabric.Rect({
width: 100,
height: 100,
top: 200,
left: 100,
fill: "#666600"
})
);
canvasRef.current.requestRenderAll();
}, 1000);
}, []);
For some reason, only the object added immediately after the canvas was initialized responds to the mouse:over
event.
The other 2 rectangles added later (one with timeout, the other in a useEffect
hook based on change of state) do not log the target when hovering.
I'm not sure if this is because fabric JS interacts in a strange way with react or something else, but I'd appreciate if someone can point me in the right direction here.
See this codesandbox for the full code:
https://codesandbox.io/s/react-fiberjs-mouseevent-test-k95zuq?file=/src/App.js
See this example that doesn't use React but uses timeouts, and somehow the hover function works properly:
https://reactjs.org/docs/strict-mode.html
With Strict Mode starting in React 18, whenever a component mounts in development, React will simulate immediately unmounting and remounting the component:
So useEffect
is called twice. You should properly deinitialize the component. For example:
useEffect(() => {
...
return () => canvasRef.current.dispose();
}, [])