Framer-motion 拖动不尊重先前更新的道具

Sam*_*l G 7 javascript framer-motion

一个简单的用例是允许用户单击按钮以在滑块中分页或拖动。两个事件都paginate使用参数调用相同的函数来前进或后退——简单的东西。

然而,拖动触发似乎会导致奇怪的行为,其中滑块想要从几张幻灯片开始动画,就好像它忽略了更新的道具一样。使用按钮时不会发生这种情况,并且两者都使用相同的简单paginate调用。

任何提示表示赞赏。

最小的例子:

export default function App() {
  const [position, setPosition] = useState<number>(0);

  const paginate = (direction: Direction) => {
    setPosition((prev) => {
      return direction === Direction.Forward
        ? Math.max(-800, prev - 200)
        : Math.min(0, prev + 200);
    });
  };

  return (
    <div className="App">
      <Slider>
        <Wrapper
          animate={{ x: position }}
          transition={{
            x: { duration: 1, type: "tween" }
          }}
          drag="x"
          dragConstraints={{
            top: 0,
            left: 0,
            right: 0,
            bottom: 0
          }}
          onDragEnd={(e, { offset, velocity }) => {
            const swipe = swipePower(offset.x, velocity.x);

            if (swipe < -swipeConfidenceThreshold) {
              paginate(Direction.Forward);
            } else if (swipe > swipeConfidenceThreshold) {
              paginate(Direction.Back);
            }
          }}
        >
          <Slide>1</Slide>
          <Slide className="alt">2</Slide>
          <Slide>3</Slide>
          <Slide className="alt">4</Slide>
          <Slide>5</Slide>
        </Wrapper>
      </Slider>
      <button onClick={() => paginate(Direction.Back)}>prev</button>
      <button onClick={() => paginate(Direction.Forward)}>next</button>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

代码沙盒演示

dev*_*ium 1

不得不说,这个问题还蛮有趣的。不过,我想我已经找到了解决这个问题的方法。我注意到的一件事是,如果你注释掉

onDragEnd={(e, { offset, velocity }) => {
            // const swipe = swipePower(offset.x, velocity.x);
            // if (swipe < -swipeConfidenceThreshold) {
            // paginate(Direction.Forward);
            // } else if (swipe > swipeConfidenceThreshold) {
            // paginate(Direction.Back);
            // }
          }}
Run Code Online (Sandbox Code Playgroud)

整个onDragEndprop 函数,这个例子仍然不起作用,因为从表面上看,可拖动组件不尊重你的偏移量。

我意识到此时问题是组件的内部状态与您的状态不同步。您看一下吗,Framer Motion API 实际上提供了一种检查这一点的方法。 https://www.framer.com/api/motion/motionvalue/#usemotionvalue

useMotionValue()它是一个让我们能够看到实际发生的事情的钩子。事实证明,当用户开始拖动时,我们的值设置错误:

useEffect(
    () =>
      motionX.onChange((latest) => {
        console.log("LATEST: ", latest);
      }),
    []
  );
Run Code Online (Sandbox Code Playgroud)

我们可以看到这一点,因为一旦我们开始拖动,状态就会“跳”到 200。

因此理论上修复很容易,我们只需要确保让该值“知道”我们的偏移量,这样它就会以正确的偏移量开始!

无论如何,这就是我的思考过程,这是解决方案,您需要做的就是设置左侧约束以使其工作:

dragConstraints={{
            top: 0,
            left: position,
            right: 0,
            bottom: 0
          }}
Run Code Online (Sandbox Code Playgroud)

还有田田!这使它起作用。这是我的工作解决方案:https://codesandbox.io/s/lingering-waterfall-2tsfi ?file=/src/App.tsx