React中useEffect结合Animated.timing反向动画未正常显示问题
解决React中useEffect结合Animated.timing反向动画跳变的问题
嘿,我一眼就看出问题所在了——你的滑块反向切换时直接跳变,核心原因是动画状态没有被持久化。
你现在在组件里直接声明const transformX = new Animated.Value(0),每次active变化导致Slider组件重新渲染时,都会创建一个全新的Animated.Value实例,之前的动画进度直接丢失了。比如当你从Pickup切回Delivery时,新的transformX初始值就是0,这时候Animated.timing其实是从0到0,看起来就像滑块直接跳回去,而动画回调还是会执行(毕竟动画“完成”了)。
修复方案:用useRef持久化Animated.Value实例
我们需要让transformX在组件整个生命周期内保持同一个实例,这时候useRef就派上用场了,它能帮我们保存不会随渲染重置的变量。修改后的Slider组件代码如下:
const Slider = ({sliderWidth, circleHeight, active, onToggle}) => { // 用useRef保存Animated.Value,确保组件渲染时不会重新创建 const transformXRef = React.useRef(new Animated.Value(0)); const transformX = transformXRef.current; React.useEffect(() => { console.log('only run when active changed', transformX); const value = active ? sliderWidth - circleHeight : 0; console.log('value', value); Animated.timing(transformX, { toValue: value, duration: 500, useNativeDriver: true }).start(() => console.log('animation done')); }, [active, sliderWidth, circleHeight]); // 这里可以去掉transformX,因为ref的current是稳定的 return ( <View style={{position: 'absolute',width: sliderWidth+10, backgroundColor: 'white', borderBottomLeftRadius: 8, borderBottomRightRadius: 8, flexDirection: 'column', alignItems: 'center'}}> <View style={{width: sliderWidth, borderRadius: sliderWidth/2, borderWidth: 1, height: circleHeight,justifyContent: 'center', alignItems: 'center', marginTop: 8, marginBottom: 8, backgroundColor: 'white'}}> <Text style={{fontSize: 11}}> {active ? "Pickup" : "Delivery"} </Text> <TouchableOpacity onPress={onToggle} style={{position: 'absolute', left:0, transform: [{translateX: transformX}]}}> <View style={{height: circleHeight-2, width: circleHeight-2, borderRadius: circleHeight/2-1, backgroundColor: 'orange' }} /> </TouchableOpacity> </View> </View> ); };
关键修改说明:
- 用useRef保存动画值:
useRef创建的对象在组件挂载后就不会再改变,它的current属性会一直指向同一个Animated.Value实例,这样动画状态就能在组件渲染之间保留下来。 - 优化useEffect依赖:因为
transformXRef是稳定的ref对象,所以不需要把transformX加入useEffect的依赖数组,避免不必要的触发。
这样修改后,不管你是切换到Pickup还是Delivery,滑块都会从当前位置平滑过渡到目标位置,完全符合你想要的来回平滑切换效果。
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

