React Native:如何复用DrawerLayout而非每个页面重复添加?
当然不用每个页面都写DrawerLayoutAndroid!教你优雅复用+选中状态管理
嘿,作为React Native新手遇到这种重复代码的问题太正常了——每个页面都塞一遍DrawerLayoutAndroid不仅冗余,后期改个样式都要翻遍所有页面,完全没必要!我们可以把抽屉抽成可复用的自定义组件,还能轻松加上选中/未选中的状态管理,一步解决你的问题。
下面给你一步步拆解实现思路:
1. 先抽离自定义抽屉组件(带选中状态)
首先创建一个CustomDrawer.js,把抽屉的结构、样式、选中逻辑都封装在这里:
import React, { Component } from 'react'; import { View, Text, TouchableOpacity, DrawerLayoutAndroid, StyleSheet } from 'react-native'; export default class CustomDrawer extends Component { state = { selectedRoute: 'Screen1' // 默认选中第一个页面 }; // 更新选中状态并跳转页面 handleMenuPress = (routeName) => { this.setState({ selectedRoute: routeName }); this.props.navigation.navigate(routeName); this.props.closeDrawer(); // 关闭抽屉 }; // 监听页面跳转,同步选中状态 componentDidMount() { this.unsubscribe = this.props.navigation.addListener('didFocus', () => { const currentRoute = this.props.navigation.state.routeName; this.setState({ selectedRoute: currentRoute }); }); } componentWillUnmount() { this.unsubscribe(); } render() { const { selectedRoute } = this.state; const drawerContent = ( <View style={styles.drawerContainer}> <TouchableOpacity style={[styles.menuItem, selectedRoute === 'Screen1' && styles.selectedItem]} onPress={() => this.handleMenuPress('Screen1')} > <Text style={[styles.menuText, selectedRoute === 'Screen1' && styles.selectedText]}>页面1</Text> </TouchableOpacity> <TouchableOpacity style={[styles.menuItem, selectedRoute === 'Screen2' && styles.selectedItem]} onPress={() => this.handleMenuPress('Screen2')} > <Text style={[styles.menuText, selectedRoute === 'Screen2' && styles.selectedText]}>页面2</Text> </TouchableOpacity> {/* 可扩展更多菜单项 */} </View> ); return ( <DrawerLayoutAndroid ref={this.props.drawerRef} // 暴露ref给父组件控制开闭 drawerWidth={250} drawerPosition={DrawerLayoutAndroid.positions.Left} renderNavigationView={() => drawerContent} > {this.props.children} {/* 这里放StackNavigator的页面内容 */} </DrawerLayoutAndroid> ); } } const styles = StyleSheet.create({ drawerContainer: { flex: 1, paddingTop: 50, backgroundColor: '#f5f5f5' }, menuItem: { padding: 15, borderBottomWidth: 1, borderBottomColor: '#ddd' }, selectedItem: { backgroundColor: '#e0e0e0' }, menuText: { fontSize: 16 }, selectedText: { color: '#2196F3', fontWeight: 'bold' } });
2. 用容器组件包裹StackNavigator
接下来创建一个DrawerContainer.js,把你的StackNavigator作为自定义抽屉的子组件,这样所有页面都会共享同一个抽屉:
import React, { Component } from 'react'; import { createStackNavigator } from 'react-navigation-stack'; import { TouchableOpacity, Text } from 'react-native'; import CustomDrawer from './CustomDrawer'; import Screen1 from './Screen1'; import Screen2 from './Screen2'; // 创建StackNavigator const AppStack = createStackNavigator({ Screen1: { screen: Screen1 }, Screen2: { screen: Screen2 } }); export default class DrawerContainer extends Component { drawerRef = null; // 自定义头部,添加抽屉开关按钮 static navigationOptions = ({ navigation }) => ({ headerLeft: () => ( <TouchableOpacity onPress={() => navigation.getParam('openDrawer')()}> <Text style={{ padding: 10, fontSize: 20 }}>☰</Text> </TouchableOpacity> ) }); componentDidMount() { // 把控制抽屉的方法传递给StackNavigator的页面 this.props.navigation.setParams({ openDrawer: this.openDrawer, closeDrawer: this.closeDrawer }); } openDrawer = () => { this.drawerRef?.openDrawer(); }; closeDrawer = () => { this.drawerRef?.closeDrawer(); }; render() { return ( <CustomDrawer drawerRef={(ref) => (this.drawerRef = ref)} navigation={this.props.navigation} > <AppStack navigation={this.props.navigation} /> </CustomDrawer> ); } }
3. 修改你的Screen1.js(不用再写Drawer!)
现在你的Screen1里只需要专注页面逻辑,抽屉的事情交给自定义组件处理,比如你的onScreen1Click可以改成这样:
import React, { Component } from 'react'; import { View, TouchableOpacity, Text, StyleSheet } from 'react-native'; export default class Screen1 extends Component { static navigationOptions = { header: null // 不需要默认头部可以保留,或者用容器的自定义头部 }; onScreen1Click = () => { // 直接调用容器传递的closeDrawer方法 this.props.navigation.getParam('closeDrawer')(); // 跳转到其他页面 this.props.navigation.navigate('Screen2'); }; render() { return ( <View style={styles.container}> <Text style={styles.title}>这是页面1</Text> <TouchableOpacity onPress={this.onScreen1Click} style={styles.button}> <Text style={styles.buttonText}>点击跳转到页面2并关闭抽屉</Text> </TouchableOpacity> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#fff' }, title: { fontSize: 20, marginBottom: 20 }, button: { padding: 10, backgroundColor: '#2196F3', borderRadius: 5 }, buttonText: { color: '#fff', fontSize: 16 } });
这样一来,你再也不用在每个页面里重复写DrawerLayoutAndroid了,所有抽屉相关的逻辑都集中在自定义组件里,维护和修改都超级方便!而且选中状态会自动和当前页面同步,用户体验也更流畅。
内容的提问来源于stack exchange,提问作者zephyr
相关产品推荐
相关产品推荐

