Framer-Motion切换进入/退出状态时首次反向动画异常求助
问题描述
尝试根据用户操作的前进(state > prevState)或后退(state < prevState)状态为元素添加动画:
- 通过自定义
useStateWithPreviousHook跟踪当前状态与历史状态 - 在Framer-Motion的
AnimatePresence组件中配置initial和exit动画参数
目前大部分场景正常,但首次切换方向时退出动画表现异常,怀疑是定义退出过渡的变量存在闭包问题。
代码示例
自定义Hook
import { useState } from "react"; export default function useStateWithPrevious(initial) { const [value, setValue] = useState(initial); const [prev, setPrev] = useState(initial); function setValueAndPrev(newValue) { if (newValue === value) return; // 可选,根据逻辑调整 setPrev(value); setValue(newValue); } return [prev, value, setValueAndPrev]; }
Hook使用
const [previousRegistrationDay, registrationDay, setRegistrationDay] = useStateWithPrevious(1);
Framer-Motion组件
<AnimatePresence mode="wait"> <motion.nav key={registrationDay} animate={{ x: "0%", opacity: 1 }} transition={{ duration: 0.5 }} initial={{ opacity: 0, x: previousRegistrationDay < registrationDay ? "100%" : "-100%" }} exit={{ opacity: 0, x: previousRegistrationDay < registrationDay ? "-100%" : "100%" }} > <div> registrationDay{registrationDay} <br /> previousRegistrationDay{previousRegistrationDay} </div> </motion.nav> </AnimatePresence>
问题原因与解决方案
问题根源
原自定义Hook使用useState存储历史状态,而React的setState是异步批量更新的。首次调用setValueAndPrev时,prev和value的更新会在同一批次完成,但即将退出的旧组件(由AnimatePresence管理)会捕获更新前的状态值——此时previousRegistrationDay与registrationDay仍相等,导致exit动画的方向判断逻辑失效。
修复方案
将自定义Hook中的历史状态改用useRef存储,因为useRef的current属性是同步更新的,能确保在状态变化时立即获取到正确的历史值,避免闭包导致的状态捕获问题:
修改后的自定义Hook
import { useState, useRef, useEffect } from "react"; export default function useStateWithPrevious(initial) { const [value, setValue] = useState(initial); const prevRef = useRef(initial); useEffect(() => { // 每次value更新后,同步更新prevRef prevRef.current = value; }, [value]); function setValueAndPrev(newValue) { if (newValue === value) return; setValue(newValue); } // 返回prevRef.current作为历史值,当前值,更新方法 return [prevRef.current, value, setValueAndPrev]; }
额外说明
确保AnimatePresence的mode="wait"配置正确,它会等待退出动画完成后再渲染新组件,避免动画冲突。
内容的提问来源于stack exchange,提问作者Barrard
相关产品推荐
相关产品推荐

