如何让framer-motion在useState数组更新/重渲染时始终执行动画?
解决Framer Motion动画触发异常问题
核心问题本质
你遇到的问题是Framer Motion未正确识别元素的「进入状态变化」:
- 从「All」切换到特定年份时,过滤后的元素实际已存在于DOM中(仅被隐藏),不会触发进入动画
- 从特定年份切回「All」时,原有年份的元素未被标记为「重新进入」,仅新增元素触发动画
具体修复方案
1. 给元素key绑定筛选状态
不要使用固定的item.id作为唯一key,需将当前选中的年份也加入key,让Framer Motion识别每次筛选后都是全新的元素集合:
{filteredItems.map(item => ( <motion.div key={`${item.id}-${selectedYear}`} // 结合item.id和选中年份生成唯一key initial={{ opacity: 0, scale: 0.5 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.5 }} transition={{ duration: 0.3 }} className="box" > {item.year} - {item.name} </motion.div> ))}
2. 确保列表被AnimatePresence包裹
AnimatePresence是Framer Motion处理动态列表动画的核心组件,必须用它包裹你的元素列表,才能跟踪元素的进入/退出状态:
<AnimatePresence> <div className="box-container"> {filteredItems.map(item => ( // 上述motion.div代码 ))} </div> </AnimatePresence>
3. 强制容器重新渲染(备选方案)
如果第一种方法仍不生效,可给列表容器添加key={selectedYear},强制每次切换年份时重新渲染整个列表:
<AnimatePresence> <div className="box-container" key={selectedYear}> {filteredItems.map(item => ( <motion.div key={item.id} initial={{ opacity: 0, scale: 0.5 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.5 }} transition={{ duration: 0.3 }} className="box" > {item.year} - {item.name} </motion.div> ))} </div> </AnimatePresence>
修复原理
- 绑定筛选状态到
key后,每次切换年份都会改变元素的唯一标识,Framer Motion会将其视为新元素,重新触发initial到animate的过渡动画 AnimatePresence负责监听DOM元素的添加/移除,确保进入和退出动画能被正确触发
内容的提问来源于stack exchange,提问作者magnus
相关产品推荐
相关产品推荐

