这是我关于 SO 的第一个问题,希望我能正确解释。不太确定这是 React 问题还是 Interact.js 不适合这种复杂的交互 - 我希望你能看看并给出一些如何正确实现它的想法。
我正在 React (Next.js) 中使用 Interact.js 构建一个有点复杂的拖动组件。这是在 useEffect
钩子内部调用的 Interact.js 的启动:
useEffect(() => {
initInteract();
return () => {
interact(interactElement.current as any).unset();
};
}, [interactElement]);
这是我的 initInteract()
函数:
function initInteract() {
interact(interactElement.current as any).draggable({
onstart: () => {
setIsInteractAnimating(false);
setIsInteractDragged(true);
dispatch({ type: 'SET_INTERACT', payload: { cardObject: cardInfo, oldIndex: index } });
},
onmove: (event: any) => {
// important: use an arrow function with the prev state here
setInteractPosition((state) => {
const { interactMaxRotation, interactXThreshold } = BOUNDARIES;
const x = state.x + event.dx;
const y = state.y + event.dy;
let rotation = interactMaxRotation * (x / interactXThreshold);
if (rotation > interactMaxRotation) {
rotation = interactMaxRotation;
} else if (rotation < -interactMaxRotation) {
rotation = -interactMaxRotation;
}
return { x, y, rotation };
});
},
onend: () => {
setIsInteractAnimating(true);
setInteractPosition((state) => {
handleDrop(state);
return { x: 0, y: 0, rotation: 0 };
});
// reset
setIsInteractDragged(false);
},
});
}
如您所见,interact.js
在页面上移动 HTML 元素。我正在调用 setInteractPosition()
来更改元素的坐标。我使用箭头函数表示法是因为当我刚刚调用 setInteractPosition({ x: newX, y: newY, rotation: newRotation })
时它不起作用。
-> 也许这是一个异步问题,或者因为 interact.js
实例中的状态没有与组件的状态同步,因为 useEffect 只有在 interactElement
更改时才会被调用。 (interactElement
是要移动的 HTML 元素的 ref
。)
在拖动结束时调用函数 handleDrop()
并使用我的减速器中的状态变量。 (不要认为把reducer贴在这里是相关的)
函数 handleDrop()
没有应用其余部分的最新状态值。这意味着:我在拖动过程中更改了组件状态,但这些更改并未反映在 handleDrop()
函数内。我认为这是因为我在使用当时的状态值调用 initInteract()
时声明了该函数。
我尝试了很多东西。我得到的最接近的是向 useEffect
钩子添加另一个依赖变量,这是 handleDrop()
函数正常工作所必需的:
useEffect(() => {
initInteract();
return () => {
interact(interactElement.current as any).unset();
};
}, [interactElement, draftState.interact.oldIndex]);
好消息:handledrop()
可以很好地适应此更改!
坏消息:拖动动画滞后。我需要“两次”拖动元素才能正确拖动它。一旦我拖了一点,我就不能再拖了。当我之后再次拖动它时,它起作用了。这是因为在拖动开始时设置了 draftState.interact.oldIndex
(通过 dispatch({ type: 'SET_INTERACT', payload: { cardObject: cardInfo, oldIndex: index } })
),我假设 interact.js
元素重新渲染并失去了它的引用。
在拖动时在不丢失“引用”的情况下在 initInteract()
内使用更改状态值的最佳方法是什么?
我应该尝试使用类组件吗?
我非常感谢您的任何想法和指示。非常感谢您的帮助!