React中return语句前置导致条件渲染失效及滑块动画异常如何解决
React Native 抽离公共滑块组件后保留滑动动画并正常切换页面的实现方案
核心问题原因
- React组件的render方法仅支持返回一个根节点,你提前单独返回Slider组件,自然会导致后续的条件渲染逻辑无法执行
- 之前滑块放在页面内部,每次切换页面时滑块都会被卸载后重新挂载,内部维护的动画状态会被重置,自然无法展示完整滑动效果
修改方案
1. 修改App.js的render逻辑
将Slider组件抽离到外层根容器中,不随页面条件渲染卸载,页面部分作为子节点条件渲染即可,修改后代码如下:
import React from 'react'; import { View } from 'react-native'; import Slider from './Slider'; // 按你实际路径调整 import ListHome from './ListHome'; import MapHome from './MapHome'; export default class App extends React.Component { constructor(props) { super(props); this.state = { whichComponentToShow: "Screen1" }; } goToMap = () => { this.setState({ whichComponentToShow: "Screen2" }); }; goToList = () => { this.setState({ whichComponentToShow: "Screen1" }); }; render() { const { whichComponentToShow } = this.state; return ( <View style={{backgroundColor: '#d1cfcf' ,flex: 1}}> {/* 滑块放在外层,不会随页面切换卸载,动画状态保留 */} <Slider renderList={this.goToList} renderMap={this.goToMap} /> {/* 条件渲染对应页面 */} {whichComponentToShow === 'Screen1' && <ListHome />} {whichComponentToShow === 'Screen2' && <MapHome />} </View> ); } }
2. 调整Slider组件样式
原Slider外层的flex:1会占满整个屏幕,导致下方页面被挤出可视区域,调整样式即可:
import React, { useState, useRef, useEffect } from 'react'; import { SafeAreaView, View, Animated, TouchableOpacity, Text, Dimensions } from 'react-native'; const Slider = (props) => { const [active, setActive] = useState(false) let transformX = useRef(new Animated.Value(0)).current; useEffect(() => { if (active) { Animated.timing(transformX, { toValue: 1, duration: 300, useNativeDriver: true }).start() } else { Animated.timing(transformX, { toValue: 0, duration: 300, useNativeDriver: true }).start() } }, [active]); const rotationX = transformX.interpolate({ inputRange: [0, 1], outputRange: [2, Dimensions.get('screen').width / 4] }) return ( <SafeAreaView style={{ // 去掉flex:1,添加边距适配布局 alignItems: 'center', marginVertical: 20 }}> <View style={{ flexDirection: 'row', position: 'relative', height: 45, width: 240, borderRadius: 10, backgroundColor: 'white', marginHorizontal: 5 }}> <Animated.View style={{ position: 'absolute', height: 45 - 2*2, top: 2, bottom: 2, borderRadius: 10, width: Dimensions.get('screen').width / 3 - 3.5 , transform: [ { translateX: rotationX } ], backgroundColor: '#d1cfcf', }} > </Animated.View> <TouchableOpacity style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }} onPress={() => {setActive(false); props.renderList() }}> <Text> List </Text> </TouchableOpacity> <TouchableOpacity style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }} onPress={() => {setActive(true); props.renderMap() }}> <Text> Map </Text> </TouchableOpacity> </View> </SafeAreaView> ); } export default Slider
可选优化
如果需要保证滑块状态和当前页面永远同步,可以将Slider内部的active状态提到App的state中,和whichComponentToShow绑定(Screen1对应false,Screen2对应true),避免其他逻辑切换页面后滑块和页面状态不一致的问题。
内容的提问来源于stack exchange,提问作者Justin Priede
相关产品推荐
相关产品推荐

