Framer-motion 拖动不尊重以前更新的道具
Framer-motion drag not respecting previously updated props
一个简单的用例是允许用户单击按钮以在滑块中分页或拖动。这两个事件都调用相同的 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>
);
}
不得不说,这个问题很有意思。不过,我想我想出了一个办法让你处理这个问题。我注意到的一件事是,如果您注释掉
onDragEnd={(e, { offset, velocity }) => {
// const swipe = swipePower(offset.x, velocity.x);
// if (swipe < -swipeConfidenceThreshold) {
// paginate(Direction.Forward);
// } else if (swipe > swipeConfidenceThreshold) {
// paginate(Direction.Back);
// }
}}
整个 onDragEnd
道具功能,这个例子仍然不起作用,因为从外观上看,可拖动组件不符合您的偏移量。
我意识到此时,问题是组件的内部状态与您的状态不同步。你会看一下吗,Framer Motion API 实际上提供了一种检查它的方法。
https://www.framer.com/api/motion/motionvalue/#usemotionvalue
它是钩子 useMotionValue()
让我们看到实际发生了什么。事实证明,当用户开始拖动时我们的值设置错误:
useEffect(
() =>
motionX.onChange((latest) => {
console.log("LATEST: ", latest);
}),
[]
);
我们可以看到这一点,因为我们一开始拖动,状态就“跳”到 200。
所以理论上修复很容易,我们只需要确保让那个值“知道”我们的偏移量,这样它就会以正确的偏移量开始!
无论如何,这就是我的思考过程,这是解决方案,您需要做的就是设置左约束以使其工作:
dragConstraints={{
top: 0,
left: position,
right: 0,
bottom: 0
}}
还有田田!这使它工作。这是我的工作解决方案:https://codesandbox.io/s/lingering-waterfall-2tsfi?file=/src/App.tsx
一个简单的用例是允许用户单击按钮以在滑块中分页或拖动。这两个事件都调用相同的 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>
);
}
不得不说,这个问题很有意思。不过,我想我想出了一个办法让你处理这个问题。我注意到的一件事是,如果您注释掉
onDragEnd={(e, { offset, velocity }) => {
// const swipe = swipePower(offset.x, velocity.x);
// if (swipe < -swipeConfidenceThreshold) {
// paginate(Direction.Forward);
// } else if (swipe > swipeConfidenceThreshold) {
// paginate(Direction.Back);
// }
}}
整个 onDragEnd
道具功能,这个例子仍然不起作用,因为从外观上看,可拖动组件不符合您的偏移量。
我意识到此时,问题是组件的内部状态与您的状态不同步。你会看一下吗,Framer Motion API 实际上提供了一种检查它的方法。 https://www.framer.com/api/motion/motionvalue/#usemotionvalue
它是钩子 useMotionValue()
让我们看到实际发生了什么。事实证明,当用户开始拖动时我们的值设置错误:
useEffect(
() =>
motionX.onChange((latest) => {
console.log("LATEST: ", latest);
}),
[]
);
我们可以看到这一点,因为我们一开始拖动,状态就“跳”到 200。
所以理论上修复很容易,我们只需要确保让那个值“知道”我们的偏移量,这样它就会以正确的偏移量开始!
无论如何,这就是我的思考过程,这是解决方案,您需要做的就是设置左约束以使其工作:
dragConstraints={{
top: 0,
left: position,
right: 0,
bottom: 0
}}
还有田田!这使它工作。这是我的工作解决方案:https://codesandbox.io/s/lingering-waterfall-2tsfi?file=/src/App.tsx