Performance issues with useDragLayer hook
See original GitHub issueDescribe the bug I am animating a hand of playing cards. I translate each card individually when it is dragged (instead of having a drag preview), therefore I have 1 custom drag layer per card. The performances was dropping with the number of cards in hand, so I tried to avoid listening to the client offset in each drag layer. It turn out it is not possible given the current implementation of useDragLayer hook.
The 2 “useEffect” hooks inside useDragLayer looks pretty strange to me: why would you want to subscribe to something every time your component rerenders? It turns out that inside the monitor, we add a listener to the redux store each time.
I tried to reimplement useDragLayer but with only a single subscription when the hook is created: it does not work. I could not understand why the listener of the redux store is never called when I did that.
Expected behavior I want to be able to collect the offset values conditionally in useDragLayer hook, in order to have multiple hooks but only one which causes the component to rerender. Also, I think the spamming of listener into the redux store should be fixed to improve the performances.
Workaround I created a custom specialized hook which performs much better:
const useDragOffsetDiff = (enabled: Boolean) => {
const {dragDropManager} = useContext(DndContext)
invariant(dragDropManager != null, 'Expected drag drop context')
const monitor = (dragDropManager as DragDropManager).getMonitor()
const [dragOffsetDiff, setDragOffsetDiff] = useState(monitor.getDifferenceFromInitialOffset())
const offsetChangeListener = () => setDragOffsetDiff(monitor.getDifferenceFromInitialOffset())
const [intervalId, setIntervalId] = useState<NodeJS.Timeout>()
useEffect(() => {
if (enabled) {
setIntervalId(setInterval(offsetChangeListener, 40))
} else if (intervalId) {
clearInterval(intervalId)
}
}, [enabled])
return dragOffsetDiff
}
Right now I could not find another way than setInterval to collect the offset. The store is not exposed by the DragDropManager, so I could not add my own listener to it.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:15 (2 by maintainers)
Top GitHub Comments
I just came up with a better workaround, by listening to the redux store instead of setting an interval:
I just came with a far better solution. This is how I use “useDragLayer” and prevent it from spamming too many changes:
A few examples of drag&drop using this hook are available on my website: https://game-park.com/