Draggable not working with React useState and useEffect hooks
demo: https://stackblitz.com/edit/react-ts-jeqtzy?file=App.jsx
Issue description
Draggable can not be moved if React setState method is called within a 'dragmove' event listener (which is defined within a useEffect hook).
Steps to reproduce:
- add an interactjs event listener for a draggable inside a useEffect hook
- set react useEffect dependency list as []
- call react setState method inside the event listener
Expected behavior
Draggable should move freely with mouse drag.
Actual behavior
Draggable get stuck and can't be moved away from it's original position.
System configuration
interact.js version: 1.10.11 react.js version: 18.1.0 Browser name and version: Chrome 101.0.4951.64 (Official Build) (x86_64) Operating System: macOS Catalina 12.3.1
Other observations
The same functionality would work under all these different scenarios:
- Draggable component is a React class component instead of a functional component
- useEffect dependency list is removed
- setState method is not called
- event listener is defined outside of a useEffect hook
Code example
import interact from "interactjs";
import React, { useEffect, useState } from "react";
export default function Draggable() {
const [positionX, setPositionX] = useState(0);
useEffect(() => {
interact('.draggable').draggable({
listeners: {
start(event) {
console.log(event.type, event.target)
},
move(event) {
let positionx = positionX + event.dx
event.target.style.transform =
`translate(${positionx}px)`
setPositionX(positionx)
},
}
})
},[]);
return (
<>
<div className="draggable">Drag me</div>
</>
);
}
Can you make a demo on https://jsfiddle.net/?
The positionX that the listener sees within useEffect doesn't get updated by setPositionX.
It should work if you use useRef instead of useState like this:
const positionX = useRef(0)
// ...
positionX.current += event.dx
event.target.style.transform = `translate(${positionX.current}px)`
As @taye mentioned, you should use useRef.
interact.js works very well with react.
Here is what I tried with interact.js
@taye what time support in useEffect use useState
@taye what time support in drag use useState