【React Native】React Navigation 5.x的使用

在App中,底部 TabBar
导航和顶部的导航栏导航是最常见的页面导航方式,而 React Native
官方推荐的第三方库是 @react-navigation
,正好今年 React Navigation
发布了5.0版本,与前面的版本差别还挺大,不过使用上更方便了。本文主要讲解 React Navigation
5.0及以上版本的使用。

安装

安装核心包

# NPM
npm install @react-navigation/native
# Yarn
yarn add @react-navigation/native

安装依赖

# NPM
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
#Yarn
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

React Native0.60及以上版本是自动链接库的,不需要手动运行 react-native link
,但如果你用 React Native
开发的是iOS,还需要手动安装 pods
来完成库的链接:

npx pod-install ios

把下面这行代码放在入口文件的顶部,比如 index.js
或者 App.js

import 'react-native-gesture-handler';

最后需要用 NavigationContainer
将整个App包裹起来,这个代码一般也是放在入口文件,类似下面这样:

import 'react-native-gesture-handler';
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';

export default function App() {
  return (
    {/* Rest of your app code */}
  );
}

注意:如果你同时也使用了 Redux
框架,需要把 Provider
放在最外层,将 NavigationContainer
包裹在次外层,类似下面这样:

export default class App() {
  return (
    
      
        {/* Screen configuration */}
      
    
  );
}

使用

React Navigation有多种导航方式: Stack Navigation
Tab Navigation
Drawer Navigation
。这里主要讲 Stack Navigation
Tab Navigation

顶部导航栏导航

首先需要安装相应的库:

#NPM
npm install @react-navigation/stack
#Yarn
yarn add @react-navigation/stack

Stack Navigation
使用上相对来说比较简单,只需要把需要导航的页面组件封装成 Stack.Screen
,然后包裹在 Stack.Navigator
就可以了,最上面的 Stack.Screen
就是默认页面。

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

function App() {
  return (
    
      
        
      
      
      
    
  );
}

export default App;

也可以在 Stack.Screen
中设置导航栏的属性,设置导航栏属性 options
有两种方式,一种是带 route
参数的,一种是直接设置

/* 带route参数的options */
 ({
        headerTitle: route.name,
        headerStyle: {
            backgroundColor: '#01aaff',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
            fontWeight: 'bold',
        },
        headerRight: () => (
            

注意: React
框架使用的是虚拟 DOM
,使用 diff
算法刷新页面显示,在 Stack.Screen
中,需要添加 key
属性,否则会报警告。
在需要跳转到其他页面时只需要以下代码就可以了,后面跟的是参数。

function HomeScreen({ navigation }) {
  return (
    
      Home Screen
      

如果是用 class
方式创建的页面,代码会像下面这样:

export default class HomeScreen extends Component {
    render() {
        return (
            
                Home Screen
                

注意:导航跳转可以使用 navigation.navigate
或者 navigation.push
。如果使用 navigate
,会查找当前堆栈中是否有名字一样的路由,如果没有才创建新的路由并跳转,而 push
则会直接创建一个新的路由并跳转,也就是说可以重复多次跳转同一个页面。
堆栈导航的返回方式如下:

// 返回到上一页面
navigation.goBack()
// 返回到堆栈里第一个页面
navigation.popToPop()

底部导航栏导航

除了顶部导航栏,最常用的就是底部导航栏了,首先也需要安装相应的库:

# NPM
npm install @react-navigation/bottom-tabs
# Yarn
yarn add @react-navigation/bottom-tabs

底部导航栏的使用方法类似,需要将这些页面组件包装成 Tab.Screen
,导航则由框架内部完成,不需要手动控制:

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    
      
        
        
      
    
  );
}

底部导航栏属性可以按如下方式设置:

 ({
          tabBarIcon: ({ focused, color, size }) => {
            let iconName;

            if (route.name === 'Home') {
              iconName = focused
                ? 'ios-information-circle'
                : 'ios-information-circle-outline';
            } else if (route.name === 'Settings') {
              iconName = focused ? 'ios-list-box' : 'ios-list';
            }
            return ;
          },
        })}
        tabBarOptions={{
          activeTintColor: 'tomato',
          inactiveTintColor: 'gray',
        }}
      >
        
        
      

顶部堆栈导航栏与底部导航栏嵌套

Stack Navigation
Tab Navigation
可以相互多层嵌套,比如登录页跳转到带底部导航栏的主页面,需要把登录相关面和 Tab.navigator
一同放到同一个堆栈中,但官方不推荐这种方式,嵌套层次太多会导致维护起来特别麻烦。官方推荐使用一个变量控制当前显示的页面,把不相关的模块隔离在不同的堆栈中,类似下面这样:

const commonScreens = {
  Help: HelpScreen,
};

const authScreens = {
  SignIn: SignInScreen,
  SignUp: SignUpScreen,
};

const userScreens = {
  Home: HomeScreen,
  Profile: ProfileScreen,
};


  {Object.entries({
    ...commonScreens,
    ...(isLoggedIn ? userScreens : authScreens),
  }).map(([name, component]) => (
    
  ))}
;

isLoggedIn
这样的全局变量动态刷新页面使用 Redux
架构实现起来会简单一些,具体实现可以参考 这篇教程