如何基于React State数组实现任务状态切换的下落动画?
实现React任务项下落动画的可用库
你需要的是列表项位置变化时的平滑过渡动画,以下几个主流库可以解决这个问题,结合你的任务排序场景给出具体用法:
1. React Transition Group(官方替代方案)
这是ReactCSSTransition废弃后官方推荐的库,其中TransitionGroup组件专门处理列表元素的增删、排序动画。
核心用法示例:
import { TransitionGroup, CSSTransition } from 'react-transition-group'; // 点击标记任务完成并重新排序 const handleTaskComplete = (taskId) => { setTasks(prevTasks => { // 更新当前任务的completed状态 const updatedTasks = prevTasks.map(task => task.id === taskId ? { ...task, completed: true } : task ); // 重新排序:未完成在前,已完成在后 return [...updatedTasks.filter(t => !t.completed), ...updatedTasks.filter(t => t.completed)]; }); }; // 渲染部分 <div> <TransitionGroup> {tasks.map((elem) => ( <CSSTransition key={elem.id} timeout={500} classNames="fall"> <div onClick={() => handleTaskComplete(elem.id)}> {elem.name} </div> </CSSTransition> ))} </TransitionGroup> </div>
对应的CSS动画:
/* 进入/退出初始状态 */ .fall-enter, .fall-exit { transform: translateY(0); opacity: 1; } /* 动画执行状态 */ .fall-enter-active, .fall-exit-active { transform: translateY(100%); opacity: 0.8; transition: transform 500ms ease-in-out, opacity 500ms ease; }
2. Framer Motion
目前最流行的React动画库,API简洁,支持自动识别列表元素位置变化并生成过渡动画。
核心用法示例:
import { motion } from 'framer-motion'; // 点击处理逻辑同前 const handleTaskComplete = (taskId) => { setTasks(prevTasks => { const updatedTasks = prevTasks.map(task => task.id === taskId ? { ...task, completed: true } : task ); return [...updatedTasks.filter(t => !t.completed), ...updatedTasks.filter(t => t.completed)]; }); }; // 渲染部分 <div> {tasks.map((elem) => ( <motion.div key={elem.id} layout // 自动处理位置变化的过渡动画 transition={{ type: "spring", stiffness: 300, damping: 30 }} onClick={() => handleTaskComplete(elem.id)} > {elem.name} </motion.div> ))} </div>
只需给元素添加layout属性,Framer Motion会自动计算位置差并生成自然的下落动画,无需手动编写复杂CSS。
3. React Spring
基于物理引擎的动画库,适合追求自然动效的场景,对列表排序动画支持完善。
核心用法示例:
import { useTransition, animated } from 'react-spring'; // 定义过渡动画规则 const transitions = useTransition(tasks, { key: task => task.id, from: { transform: 'translateY(0)', opacity: 1 }, update: { transform: 'translateY(0)', opacity: 1 }, leave: { transform: 'translateY(100%)', opacity: 0.6 }, config: { tension: 200, friction: 20 } }); // 渲染部分 <div> {transitions((style, item) => ( <animated.div style={style} onClick={() => handleTaskComplete(item.id)} > {item.name} </animated.div> ))} </div>
通过useTransition可以精准控制元素进入、更新、离开时的动画状态,物理参数配置能让下落动效更贴合真实世界的运动规律。
关键注意事项
- 必须给每个列表项设置唯一的
key(不要用数组索引),否则动画库无法正确识别元素的变化。 - 排序逻辑要确保生成新的数组(而非修改原数组),触发组件重渲染后,动画库才能捕获到元素位置的变化。
内容的提问来源于stack exchange,提问作者ch3tt
相关产品推荐
相关产品推荐

