如何使用Framer Motion在每次状态变更时重新触发动画
问题根因
Framer Motion 默认仅在animate、variants等动画配置属性发生变更时才会触发新的动画过渡,你当前代码中initial="hide"和animate="show"在组件首次挂载后就没有发生过变化,因此即便组件因为state更新重渲染,也不会重新执行入场动画。
解决方案
方案1:绑定动态key(最适配当前场景,修改成本最低)
给motion组件添加key属性,值绑定到你每次会更新的state变量。React在检测到key值变化时,会销毁旧的组件实例、重新挂载新实例,自然会重新触发从hide到show的完整动画流程。
修改后的完整代码如下:
import React, { useEffect, useState } from "react"; import { motion} from "framer-motion"; import styled from "styled-components"; const Screen = () => { const [state, setState] = useState(1); useEffect(() => { setInterval(() => { setState(Math.random()); }, 4000); }, []); return ( {/* 仅新增了key={state}这一行配置 */} <Title key={state} variants={variants} animate="show" initial="hide"> {console.log("re-render")} {`screen ${state}`} </Title> ); }; const Title = styled(motion.div)` color: red; `; export const variants = { show: { opacity: 1, y: 0, transition: { ease: "easeOut", duration: 0.3 } }, hide: { y: -20, opacity: 0 } }; export default Screen;
方案2:使用useAnimation钩子手动控制
如果不想频繁销毁重建组件,可以使用useAnimation钩子手动控制动画播放时机,监听state变化后主动触发动画重置和播放:
import React, { useEffect, useState } from "react"; import { motion, useAnimation } from "framer-motion"; import styled from "styled-components"; const Screen = () => { const [state, setState] = useState(1); const controls = useAnimation(); useEffect(() => { setInterval(() => { setState(Math.random()); }, 4000); }, []); // 监听state变化,每次变更时先重置到隐藏状态,再播放显示动画 useEffect(() => { controls.start("hide").then(() => { controls.start("show"); }); }, [state, controls]); return ( <Title variants={variants} animate={controls} initial="hide"> {console.log("re-render")} {`screen ${state}`} </Title> ); }; const Title = styled(motion.div)` color: red; `; export const variants = { show: { opacity: 1, y: 0, transition: { ease: "easeOut", duration: 0.3 } }, hide: { y: -20, opacity: 0, // 隐藏动画设置为0时长,无过渡直接跳转状态 transition: { duration: 0 } } }; export default Screen;
内容的提问来源于stack exchange,提问作者me-me
相关产品推荐
相关产品推荐

