I am using react-scratchcard-v2 to create a scratchcard game. It works fine on desktop, but when using it with touch (either on mobile or in the mobile view of Dev Tools), it still works, but I get his error:
react-dom.development.js:6878 Unable to preventDefault inside passive event listener invocation. preventDefault @ react-dom.development.js:6878 Scratch2._this.handleMouseMove @ index.tsx:197 callCallback2 @ react-dom.development.js:4164 invokeGuardedCallbackDev @ react-dom.development.js:4213 invokeGuardedCallback @ react-dom.development.js:4277 invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291 executeDispatch @ react-dom.development.js:9041 processDispatchQueueItemsInOrder @ react-dom.development.js:9073 processDispatchQueue @ react-dom.development.js:9086 dispatchEventsForPlugins @ react-dom.development.js:9097 (anonymous) @ react-dom.development.js:9288 batchedUpdates$1 @ react-dom.development.js:26140 batchedUpdates @ react-dom.development.js:3991 dispatchEventForPluginEventSystem @ react-dom.development.js:9287 dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465 dispatchEvent @ react-dom.development.js:6457 dispatchContinuousEvent @ react-dom.development.js:6444
That's my code:
import "./style.css";
import { useEffect, useState } from "react";
import ScratchCard from "react-scratchcard-v2";
const scratchingSound = new Audio("./sounds/scratching.mp3");
scratchingSound.loop = true;
interface IScratchAreaProps {
value: 0 | 10 | 100 | 1000;
}
const ScratchArea = ({ value }: IScratchAreaProps) => {
const [
amount,
// setAmount
] = useState(value);
const [
amountSrc,
// setAmountSrc
] = useState(`./assets/${amount}.svg`);
const [
iconSrc,
// setIconSrc
] = useState(amount === 0 ? "./assets/banana.svg" : "./assets/coin.svg");
const [isClicked, setIsClicked] = useState(false);
const [isScratching, setIsScratching] = useState(false);
const handleMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
if (event.button === 0) {
setIsClicked(true);
setIsScratching(true);
}
};
const handleMouseUp = () => {
setIsClicked(false);
setIsScratching(false);
};
const handleMouseEnter = () => {
if (isClicked) {
setIsScratching(true);
}
};
const handleMouseLeave = () => {
if (isClicked) {
setIsScratching(false);
}
};
useEffect(() => {
const handleWindowMouseUp = () => {
if (isClicked) {
setIsClicked(false);
setIsScratching(false);
}
};
window.addEventListener("mouseup", handleWindowMouseUp);
return () => {
window.removeEventListener("mouseup", handleWindowMouseUp);
};
}, [isClicked]);
useEffect(() => {
const handleWindowMouseUp = () => {
if (isClicked) {
setIsClicked(false);
setIsScratching(false);
}
};
window.addEventListener("mouseup", handleWindowMouseUp);
return () => {
window.removeEventListener("mouseup", handleWindowMouseUp);
};
}, [isClicked]);
useEffect(() => {
if (isScratching) {
scratchingSound.currentTime = 0;
scratchingSound.volume = 0.3;
scratchingSound.play();
} else {
scratchingSound.pause();
}
}, [isScratching]);
return (
<div
className="scratcharea-container"
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<ScratchCard
width={170}
height={170}
image="./assets/scratch_card.svg"
finishPercent={60}
onComplete={() => console.log("complete")}
brushSize={15}
fadeOutOnComplete={false}
>
<div className="scratcharea">
<img className="revealed-icon" alt="revealed icon" src={iconSrc} />
<img
className="revealed-amount"
alt="revealed amount"
src={amountSrc}
/>
</div>
</ScratchCard>
<div
onClick={() => console.log("Help modal opened!")}
className="help-button"
/>
</div>
);
};
export default ScratchArea;
I tried removing all event handlers, but the error persists. There is also a live deployment if you want to check it: Deployment
Thanks for any help.