如何确保元素从数组移除前先执行CSS淡出动画?
问题解决:元素移除前执行淡出动画
问题核心
你当前的代码里,在触发淡出类的同时立刻调用setData把元素从数组中移除了——React会直接卸载这个Item组件,动画还没来得及执行就被清理了,自然看不到效果。
解决方案思路
把「添加淡出类」和「移除元素」拆成两步:先给元素加淡出类让动画完整执行,等动画结束后再从数组里删掉这个元素。
修改后的完整代码
父组件(Items.jsx)
function Items() { const [data, setData] = useState([]); const [removingItemId, setRemovingItemId] = useState(null); useEffect(() => { // 替换成你的实际API请求逻辑 fetch('/your-api-url') .then(res => res.json()) .then(response => setData(response)); }, []); // 处理移除逻辑:先标记要移除的元素,等动画跑完再删 const handleRemove = (itemId) => { setRemovingItemId(itemId); // 动画时长是0.3s,所以等300ms后更新数据 setTimeout(() => { setData(prev => prev.filter(item => item.id !== itemId)); setRemovingItemId(null); }, 300); }; return ( <div className="items"> {data.map(item => ( <Item key={item.id} item={item} isRemoving={item.id === removingItemId} onRemove={() => handleRemove(item.id)} /> ))} </div> ) } export default Items;
子组件(Item.jsx)
function Item({ item, isRemoving, onRemove }) { useEffect(() => { const endTime = new Date(item.endTime); const checkExpired = () => { const now = new Date(); const remainingSeconds = Math.floor((endTime.getTime() - now.getTime()) / 1000); if (remainingSeconds < 0) { onRemove(); } }; const intervalId = setInterval(checkExpired, 1000); return () => clearInterval(intervalId); }, [item, onRemove]); return( <div className={`item ${isRemoving ? 'item--fadeout' : ''}`}> {item.title} </div> ) } export default Item;
SCSS样式
.item { border-bottom: 1px solid #e5e5e5; overflow: hidden; clear: both; // 用过渡代替动画更简洁,效果一致 transition: opacity 0.3s linear; &--fadeout { opacity: 0; } } // 如果偏好使用动画,也可以保留这段(上面的transition可以删掉) // @keyframes fadeout { // 0% { opacity: 1; } // 100% { opacity: 0; } // } // .item--fadeout { // animation: fadeout 0.3s linear forwards; // }
关键调整点
- 数据流优化:子组件不再直接操作父组件的
data状态,而是通过回调通知父组件处理移除,符合React单向数据流原则,代码更易维护。 - 时序控制:用
setTimeout等待动画完全执行后再更新数组,确保用户能完整看到淡出效果。 - 样式修正:去掉了动画里的
display: none——这个属性无法被动画过渡,而且组件最终会被React卸载,不需要CSS控制显示隐藏。
内容的提问来源于stack exchange,提问作者zeropsi
相关产品推荐
相关产品推荐

