react-navigation的各种导航嵌套优劣势

前言

默认你已经对(Stac/Drawer/Tab)三种导航已经有了基本的了解(V6版本),另外我下面提供的demo都是可直接copy运行的,要是运行不了,那就自行debug下吧

如果期望对react-navigation快速的有个系统的了解,点击查看react-navigation v6 中文极速版

一、Tab嵌套Stack

  1. 代码示例

    import * as React from 'react'
    import {Button, Text, View, StyleSheet} from 'react-native'
    import {createNativeStackNavigator} from '@react-navigation/native-stack'
    import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'
    import {NavigationContainer} from '@react-navigation/native'
    
    const STYLE = StyleSheet.create({
      center: {
        flex: 1, justifyContent: 'center', alignItems: 'center'
      }
    })
    
    function Screen3() {
      return (
        <View style={STYLE.center}>
          <Text>Screen 3</Text>
        </View>
      )
    }
    
    function Screen1({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 1</Text>
          <Button
            title="一层一层进入 Screen3"
            onPress={() => navigation.navigate('BStack', {screen: 'Screen3'})}
          />
          <Button 
            title="直接进入Go to Screen3" 
            onPress={() => navigation.navigate('Screen3')} />
        </View>
      )
    }
    
    function Screen2({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 2</Text>
          <Button title="直接进入 Screen3" onPress={() => navigation.navigate('Screen3')} />
        </View>
      )
    }
    
    const HomeStack = createNativeStackNavigator()
    
    function AStackScreen() {
      return (
        <HomeStack.Navigator>
          <HomeStack.Screen name="Screen1" component={Screen1} />
          <HomeStack.Screen name="Screen3" component={Screen3} />
        </HomeStack.Navigator>
      )
    }
    
    const SettingsStack = createNativeStackNavigator()
    
    function BStackScreen() {
      return (
        <SettingsStack.Navigator>
          <SettingsStack.Screen  name="Screen2" component={Screen2} />
          <SettingsStack.Screen name="Screen3" component={Screen3} />
        </SettingsStack.Navigator>
      )
    }
    
    const Tab = createBottomTabNavigator()
    
    export default function Demo01Navigator() {
      return (
        <NavigationContainer>
    	  <Tab.Navigator screenOptions={{headerShown: false}}>
    	    <Tab.Screen name="AStack" component={AStackScreen} />
    	    <Tab.Screen name="BStack" component={BStackScreen} />
    	  </Tab.Navigator>
        </NavigationContainer>
      )
    }
    
  2. 结构

    Tab
      AStack
        Screen1
        Screen3
      BStack
        Screen2
        Screen3
    
  3. 一些特性

    1. 因为最外层是Tab,因此所有跳转的Screen底部都会有TabBar
    2. 跳转同栈下的Screen,可以直接跳转,比如Screen1跳转到AStack中的Screen3的方式如下:navigation.navigate(‘Screen3’)
    3. 跳转不同栈的Screen,禁止直接跳转,需要指定层级,比如Screen1跳转到BStack中的Screen3的方式如下:navigation.navigate(‘BStack’, {screen: ‘Screen3’}),并且该case下也直接触发了Tab的切换

二、Stack嵌套Tab

  1. 示例代码

    import * as React from 'react'
    import {Button, Text, View, StyleSheet} from 'react-native'
    import {createNativeStackNavigator} from '@react-navigation/native-stack'
    import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'
    import {NavigationContainer} from '@react-navigation/native'
    
    const STYLE = StyleSheet.create({
      center: {
        flex: 1, justifyContent: 'center', alignItems: 'center'
      }
    })
    
    function Screen1({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 1</Text>
          <Button
            title="进入Tab下的Screen2"
            onPress={() => navigation.jumpTo('Screen2')}
          />
          <Button
            title="进入Stack下的Screen2"
            onPress={() => navigation.push('Screen2')}
          />
        </View>
      )
    }
    
    function Screen2({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 2</Text>
          <Button title="直接进入Stack下的Screen3" onPress={() => navigation.navigate('Screen3')} />
        </View>
      )
    }
    
    function Screen3({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 3</Text>
          <Button
            title="进入Tab下的Screen1"
            onPress={() => navigation.navigate('Screen1')}
          />
        </View>
      )
    }
    
    const Tab = createBottomTabNavigator()
    
    function TabNavigator() {
      return (
        <Tab.Navigator screenOptions={{headerShown: false}}>
          <Tab.Screen name="Screen1" component={Screen1} />
          <Tab.Screen name="Screen2" component={Screen2} />
        </Tab.Navigator>
      )
    }
    
    const Stack = createNativeStackNavigator()
    
    export default function Demo02Navigator() {
      return (
        <NavigationContainer>
          <Stack.Navigator>
            <Stack.Screen name="Tab" component={TabNavigator} />
            <Stack.Screen name="Screen2" component={Screen2} />
            <Stack.Screen name="Screen3" component={Screen3} />
          </Stack.Navigator>
        </NavigationContainer>
      )
    }
    
  2. 结构

    Stack
      Tab
        Screen1
        Screen2
      Screen2
      Screen3
    
  3. 一些特性

    1. 只有Tab下的Screen才有tabBar,若某个Screen即在Tab下也在Stack下,就看跳转方式了,比如在Screen1中
      • 使用jumpTo跳转到Screen2,去到的就是Tab下的Screen2(有tabBar),
      • 使用push跳转到Screen2,去到的就是Stack下的Screen2(无tabBar),
      • 使用navigate跳转到Screen2去到的也是Tab下的Screen2(有tabBar),初步分析是因为Tab初始化时路由栈中有了Screen2,在结合navigate的特性,去到Tab下的Screen2也解释得通
    2. 这种case下除了固定的tab外,其他的跳转就不需要考虑嵌套层级,直接指定名字即可
    3. 针对指定页面不显示tabBar,官方也推荐这种嵌套结构,点击查看官方说明

三、Drawer嵌套

  1. 示例代码

    import * as React from 'react'
    import {Button, Text, View, StyleSheet} from 'react-native'
    import {createNativeStackNavigator} from '@react-navigation/native-stack'
    import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'
    import {createDrawerNavigator} from '@react-navigation/drawer'
    import {NavigationContainer} from '@react-navigation/native'
    
    const STYLE = StyleSheet.create({
      center: {
        flex: 1, justifyContent: 'center', alignItems: 'center'
      }
    })
    
    function Screen1({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 1</Text>
          <Button
            title="进入Drawer下的Screen3"
            onPress={() => navigation.navigate('LeftDrawer', {screen: 'Screen3'})}
          />
        </View>
      )
    }
    
    function Screen2({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 2</Text>
        </View>
      )
    }
    
    function Screen3({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 3</Text>
          <Button
            title="打开抽屉"
            onPress={() => navigation.openDrawer()}
          />
          <Button
            title="进入Stack下的Screen4"
            onPress={() => navigation.navigate('Screen4')}
          />
        </View>
      )
    }
    
    
    function Screen4({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 3</Text>
          <Button
            title="进入Tab下的Screen1"
            onPress={() => navigation.navigate('Screen1')}
          />
        </View>
      )
    }
    
    const Tab = createBottomTabNavigator()
    
    function TabNavigator() {
      return (
        <Tab.Navigator screenOptions={{headerShown: false}}>
          <Tab.Screen name="Screen1" component={Screen1} />
          <Tab.Screen name="Screen2" component={Screen2} />
        </Tab.Navigator>
      )
    }
    
    const Drawer = createDrawerNavigator()
    
    function LeftDrawerNavigator() {
      return (
        <Drawer.Navigator
          drawerContent={() => {
            return <Text>XXXXXx</Text>
          }}
          
          screenOptions={{swipeEnabled: false, "headerShown": true, "drawerPosition": 'left'}}
        >
          <Drawer.Screen name="Screen3" options={{title: 'Screen3'}} component={Screen3} />
        </Drawer.Navigator>
      )
    }
    
    const Stack = createNativeStackNavigator()
    
    export default function Demo03Navigator() {
      return (
        <NavigationContainer>
          <Stack.Navigator initialRouteName="Tab">
            <Stack.Screen name="Tab" component={TabNavigator} />
            <Stack.Screen name="LeftDrawer" options={{"headerShown": false}} component={LeftDrawerNavigator} />
    
            <Stack.Screen name="Screen4" component={Screen4} />
          </Stack.Navigator>
        </NavigationContainer>
       
      )
    }
    
    
    
    
  2. 结构

    Stack
      Tab
        Screen1
        Screen2
      LeftDrawer
        Screen3
      Screen4
    
  3. 一些特性

    1. 只有Drawer下的Screen才有抽屉效果,若想有右边抽屉在LeftDrawer的同级增加一个RightDrawer即可,那么如何让一个Screen既有左边抽屉又有右边抽屉,有两种方案:
      1. 将Screen即放在LeftDrawer下,也放在RightDrawer下,跳转前指定栈层级即可

        这种方式让一个Screen同时只有一个导航效果,要么左要么右,具体是左还是右,取决于父级是谁

      2. Drawer的父子嵌套,详情见官方说明

        这种方式可以让一个Screen,同时拥有左右两种导航效果

    2. Drawner默认也带有导航栏,可通过options设置具体使用谁的导航栏。另外因为Drawer是嵌套在stack下,因此抽屉效果始终会在stack的导航栏下层显示
    3. 跳转有Drawer效果的页面时,需要确定他的父级,个人对这种模式很不爽,我理想的状态是在打开抽屉效果时指定左边还是右边,这种比较符合开发习惯,详情见第四种嵌套

四、Drawer作为根导航嵌套

官方的多Drawer嵌套示例

  1. 代码示例

    import * as React from 'react'
    import {Button, Text, View, StyleSheet} from 'react-native'
    import {createNativeStackNavigator} from '@react-navigation/native-stack'
    import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'
    import {NavigationContainer} from '@react-navigation/native'
    import { createDrawerNavigator } from '@react-navigation/drawer'
    
    const STYLE = StyleSheet.create({
      center: {
        flex: 1, justifyContent: 'center', alignItems: 'center'
      }
    })
    
    function Screen1({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 1</Text>
          <Button
            title="进入Scrrn3"
            onPress={() => navigation.navigate('Screen3')}
          />
        </View>
      )
    }
    
    function Screen2({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 2</Text>
        </View>
      )
    }
    
    function Screen3({navigation}: any) {
      return (
        <View style={STYLE.center}>
          <Text>Screen 3</Text>
          <Button
            title="打开左抽屉"
            onPress={() => navigation.getParent('LeftDrawer').openDrawer()}
          />
          <Button
            title="打开右抽屉"
            onPress={() => navigation.getParent('RightDrawer').openDrawer()}
          />
        </View>
      )
    }
    
    const Tab = createBottomTabNavigator()
    
    function TabNavigator() {
      return (
        <Tab.Navigator screenOptions={{headerShown: false}}>
          <Tab.Screen name="Screen1" component={Screen1} />
          <Tab.Screen name="Screen2" component={Screen2} />
        </Tab.Navigator>
      )
    }
    
    const LeftDrawer = createDrawerNavigator();
    
    const RightDrawer = createDrawerNavigator();
    
    const RightDrawerNavigator = () => {
      return (
        <RightDrawer.Navigator
          id="RightDrawer"
          screenOptions={{ drawerPosition: 'right', headerShown: false }}
        >
          <RightDrawer.Screen name="stack" component={StackNavigator} />
        </RightDrawer.Navigator>
      );
    };
    
    
    const Stack = createNativeStackNavigator()
    
    function StackNavigator() {
      return (
        <Stack.Navigator>
          <Stack.Screen name="Tab" component={TabNavigator} />
          <Stack.Screen name="Screen3" component={Screen3} />
        </Stack.Navigator>
      )
    }
    
    export default function Demo04Navigator() {
      return (
        <NavigationContainer>
          <LeftDrawer.Navigator id="LeftDrawer" screenOptions={{ drawerPosition: 'left', headerShown: false }}>
            <LeftDrawer.Screen name='LeftDrawer' component={RightDrawerNavigator}/>
          </LeftDrawer.Navigator>
        </NavigationContainer>
      )
    }
    
  2. 结构

    LeftDrawer
      RightDrawer
        Stack
          Tab
            Screen1
            Screen2
          Scrren3
          Scrren4
    
  3. 一些特性

    1. 该嵌套模式,可以实现所有的Screen都同时支持左右两种抽屉效果,并且打开哪个抽屉是在调用打开抽屉API时决定的,而非在进入当前页面时决定
    2. 因为抽屉是根路由,因此抽屉效果是覆盖在stack的navBar上
    3. 这种嵌套在web上加载首页时会快速的显示左右抽屉并消失,目前没有找到合适的解决方案

五、总结

没有最好,只有最适合自己业务的,大家可根据业务情况做抉择,或者扩展出更适合自己业务的导航嵌套模式

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值