这是我一直用来在 SVG 元素上注册拖动事件的通用自定义钩子。
import { useState, useEffect, useCallback, useRef } from 'react'
// You may need to edit this to serve your specific use case
function getPos(e) {
return {
x: e.pageX,
y: e.pageY,
}
}
// from https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
function usePrevious(value) {
const ref = useRef()
useEffect(() => {
ref.current = value
})
return ref.current
}
export function useDrag({ onDrag, onDragStart, onDragEnd }) {
const [isDragging, setIsDragging] = useState(false)
const handleMouseMove = useCallback(
(e) => {
onDrag(getPos(e))
},
[onDrag]
)
const handleMouseUp = useCallback(
(e) => {
onDragEnd(getPos(e))
document.removeEventListener('mousemove', handleMouseMove);
setIsDragging(false)
},
[onDragEnd, handleMouseMove]
)
const handleMouseDown = useCallback(
(e) => {
onDragStart(getPos(e))
setIsDragging(true)
document.addEventListener('mousemove', handleMouseMove)
},
[onDragStart, handleMouseMove]
)
const prevMouseMove = usePrevious(handleMouseMove)
useEffect(
() => {
document.removeEventListener('mousemove', prevMouseMove);
if(isDragging) {
document.addEventListener('mousemove', handleMouseMove)
}
},
[prevMouseMove, handleMouseMove, isDragging]
)
useEffect(
() => {
if (isDragging) {
document.addEventListener('mouseup', handleMouseUp)
}
return () => document.removeEventListener('mouseup', handleMouseUp)
},
[isDragging, handleMouseUp]
)
return handleMouseDown
}