带有 UseEffect() 钩子的 Interact.js:如何处理状态变化?

时间:2021-01-24 11:09:18

标签: javascript reactjs interact.js

这是我关于 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 元素重新渲染并失去了它的引用。

Gif that shows the bug

问题:

在拖动时在不丢失“引用”的情况下在 initInteract() 内使用更改状态值的最佳方法是什么? 我应该尝试使用类组件吗?

我非常感谢您的任何想法和指示。非常感谢您的帮助!

0 个答案:

没有答案