如何在react-swipeable-list滑动动画结束后再更新React state
react-swipeable-list滑动动画完成后执行状态更新的解决方案
你的问题核心是状态更新触发的重渲染打断了未完成的滑动回弹过渡动画,以下是三种可直接落地的解决方法:
方案1:匹配动画时长做延时更新
先确认react-swipeable-list的回弹动画时长,官方默认值为300ms,如果自定义过动画则替换为对应时长即可。在滑动事件处理函数中用setTimeout延时执行状态更新逻辑,保证动画先执行完成。
示例代码:// 滑动完成事件回调 const onSwipe = (swipedItem) => { setTimeout(() => { // 此处执行你的状态更新逻辑 setPendingList(prev => prev.filter(item => item.id !== swipedItem.id)) setNextBuyList(prev => [...prev, swipedItem]) }, 300) // 延时时长和回弹动画时长完全一致 }该方案实现成本最低,只要动画时长固定就不会出现问题。
方案2:通过React ref监听过渡结束事件
React并不禁止通过ref访问DOM节点,仅不推荐直接修改DOM属性/结构,因此你可以通过ref绑定滑动项的DOM节点,监听transitionend事件(滑动回弹属于CSS过渡动画),事件触发后再执行状态更新。
示例代码:import { useRef, useEffect, useCallback } from 'react' import { SwipeableListItem } from '@sandstreamdev/react-swipeable-list' function ShoppingItem({ item, onSwipeComplete }) { const swipeRef = useRef(null) // 用useCallback固化更新逻辑,避免重复绑定事件 const handleTransitionEnd = useCallback((e) => { // 过滤掉子元素触发的过渡事件,只响应列表项本身的回弹过渡 if (e.target === swipeRef.current && e.propertyName === 'transform') { onSwipeComplete(item) } }, [item, onSwipeComplete]) useEffect(() => { const node = swipeRef.current if (node) { node.addEventListener('transitionend', handleTransitionEnd) } return () => { if (node) { node.removeEventListener('transitionend', handleTransitionEnd) } } }, [handleTransitionEnd]) return ( <SwipeableListItem ref={swipeRef} /* 其他原有配置 */ /> ) }该方案不需要硬编码动画时长,适配自定义动画的场景。
方案3:优化重渲染范围避免打断动画
你可以将单个列表项封装为独立组件,用React.memo包裹,只有当列表项自身的props变化时才会触发重渲染。父组件状态更新时,正在执行动画的滑动项没有props变化就不会重渲染,动画会正常执行完成。
该方案可以和前两个方案搭配使用,进一步提升列表滑动的流畅度。
内容的提问来源于stack exchange,提问作者MikeTheTall
相关产品推荐
相关产品推荐

