ReactNative路由:react-navigation 6.x 的基本使用

每天对自己多问几个为什么,总是有着想象不到的收获。 一个菜鸟小白的成长之路(copyer)

react-native官网的主推方案就是一个单独的导航库react-navigation

官网地址

https://reactnavigation.org/

react-navigation有很多的版本,并且版本的变动还是很大的,对我我刚接触react-native还是从最新的版本开始学习, 最近的版本就是 6.x版本

安装

yarn add @react-navigation/native       // 安装导航库
yarn add react-native-screens react-native-safe-area-context    // 安装导航的依赖库

yarn add @react-navigation/native-stack      // 安装栈路由
yarn add @react-navigation/bottom-tabs       // 安装tab路由
yarn add @react-navigation/drawer            // 安装抽屉路由

使用

这里就结合官网的,边看边写。

1、根组件

在这里插入图片描述

要想在项目中使用路由,需要@react-navigation/native 提供的一个组件NavigationContainer在 项目的根index.js 或者 app.js中作为根组件

错误总结:

这里 NavigationContainer要作为根组件,不然会没有现象

// 错误的写法, 这里路由就没有生效
<View>
    <Text>测试项目11</Text>
    <NavigationContainer>
        <Navigator initialRouteName="Home">
            <Screen name="Home" component={
    
    Home} />
            <Screen name="About" component={
    
    About} />
        </Navigator>
    </NavigationContainer>
</View>

// 正确的写法
<NavigationContainer>
     <Text>测试项目11</Text>
     <Navigator initialRouteName="Home">
        <Screen name="Home" component={
    
    Home} />
        <Screen name="About" component={
    
    About} />
     </Navigator>
</NavigationContainer>

2、编写栈路由

在这里插入图片描述

这里使用栈路由, 就需要使用 @react-navigation/native-stack导出的一个函数createNativeStackNavigator

createNativeStackNavigator 是一个函数,返回一个对象,包含两个属性ScreenNavigator。都是用来配置react-navigation路由导航。Navigator组件应该包含 Screen组件,用来定义路由。

import React from 'react'
import {
    
     View, Text, Button } from 'react-native'
import {
    
     NavigationContainer } from '@react-navigation/native'
import {
    
     createNativeStackNavigator } from '@react-navigation/native-stack'

const Home = () => {
    
    
  return (
    <View style={
    
    {
    
    flex: 1, backgroundColor: '#84bf96', justifyContent: 'center', alignItems: 'center'}}>
      <Text>Home</Text>
    </View>
  )
}

//调用 createNativeStackNavigator 方法
const Stack = createNativeStackNavigator()
// 结构返回出来的对象
const {
    
    Navigator, Screen} = Stack

const App = () => {
    
    
  return (
    <NavigationContainer>
      // 包含关系
      <Navigator>
        // 路由配置,取名,以及渲染的组件
        <Screen name="Home" component={
    
    Home} />
      </Navigator>
  </NavigationContainer>
  )
}

export default App;

效果图:

在这里插入图片描述


3、路由跳转

在这里插入图片描述

使用 Screen组件,这个组件是一个高阶组件,会增强 props,在使用的组件中,会携带一个 navigation对象

在这个对象中,又包含一个navigate属性,是一个函数,是用来跳转 页面的,传递的参数 ,就是 在 使用 Screen中的name值的属性(简单来说,就是跟名字跳转页面)

黄色的区域: 就是说,如果传递了一个没有定义的name,那就整个程序就会报错。换一种方法来说,就是navigate的接受值,是我们已经定义好了的

<NavigationContainer>
      <Navigator initialRouteName="Home">
        <Screen name="Home" component={
    
    Home} />
        <Screen name="About" component={
    
    About} />
      </Navigator>
</NavigationContainer>

这里注册了 HomeAbout 两个name值,就是给 navigate使用的

const Home = (props) => {
    
    
  // 在props中拿到 navigation 对象
  const {
    
     navigation } = props
  return (
    <View style={
    
    {
    
    flex: 1}}>
      <Text>Home</Text>
	  // 使用navigate函数,根绝name值,来就行跳转页面
      <Button onPress={
    
    () => navigation.navigate('About')} title="跳转"/>
    </View>
  )
}

其他的方式跳转路由

在这里插入图片描述

第一段,简单来说,就是navigate接受相同的参数,是不会跳转的

navigate('about') 第一次执行,会进行调转 about页面中

navigate('about') 第二次执行,如果当前已经在about页面中,navigate函数就不会进行任何的处理。

第二段:就是我们就是想不停的近同一个页面(渲染的时候,根据传递过来的参数,渲染不同的效果,但是都是同一个组件)

那么这里就推荐push的方式,使用push方法,每次都会添加一个新的导航到导航栈中

<Button
  title="Go About"
  onPress={
    
    () => navigation.push('About')}
/>

返回的跳转方式

goBack():返回上一级

popToTop: 返回到栈顶(最开始渲染的页面)

<Button
  title="返回"
  onPress={
    
    () => navigation.goBack()}
/>
<Button
  title="返回首页"
  onPress={
    
    () => navigation.popToTop()}
/>

4、路由传参

在这里插入图片描述

路由传参,navigate 接受第二个参数,对象的形象,传递参数

组件接受路由传递的参数, route 也是 Screen组件 增强的 props, route也是一个对象 ,里面包含 一个 属性 params , 就是用来接受传递过来的参数

// Home组件: 传递参数
const Home = (props) => {
    
    
  const {
    
     navigation } = props
  return (
    <View style={
    
    {
    
    flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Home</Text>
	  // 传递参数
      <Button onPress={
    
    () => navigation.navigate('About', {
    
    name: 'copyer'})} title="跳转"/>
    </View>
  )
}
// About组件:接受参数
const About = (props) => {
    
    
  const {
    
     params } = props.route
  return (
    <View style={
    
    {
    
    flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>About</Text>
      <Text>接受的路由参数:{
    
    params.name}</Text>
    </View>
  )
}

效果图:

在这里插入图片描述

其他要点

在这里插入图片描述

组件可以跟新 params,像跟新内部 的state一样,使用 setParams()

const About = ({
     
     route, navigation}) => {
    
    
  const {
    
     params } = route
  return (
    <View style={
    
    {
    
    flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>About</Text>
      <Text>接受的路由参数:{
    
    params.name}</Text>
	  
	  // 跟新 params
      <Button title="跟新" onPress={
    
    () => navigation.setParams({
    
    
        name: 'james'
      })}></Button>
    </View>
  )
}

效果图

在这里插入图片描述

在这里插入图片描述

初始化 params,如果没有指定特别的params就会实现初始化值,并且初始化的对象,也会进行浅层的合并,使用的属性 initialParams

// 初始化的默认值
<Screen name="About" component={
    
    About} initialParams={
    
    {
    
    name: 'kobe'}} />

// 传递参数
navigation.navigate('About', {
    
    name: 'james'})

这里传递的值 》》 高于初始化的值    (展示传递的值)
// 初始化的默认值
<Screen name="About" component={
    
    About} initialParams={
    
    {
    
    name: 'kobe'}} />

// 传递参数
navigation.navigate('About', {
    
    age: '12'})


这里就会进行浅层的合并
route.params = {
    
    
    name: 'kobe',
    age: '12'
}

在这里插入图片描述

这里主要说的是: 路由传递参数的时候,应该是最小化的数据,而不会传递完整的数据,这样会造成意外的错误。(数据不同步,有些地方修改了,在路由中是体现不出来的),每个页面的数据,最好通过唯一性的值,去获取详细的数据。


5、配置路由头部

在这里插入图片描述

Screen组件 接受 options 作为 props,

options可以是一个对象,还可以是一个函数,返回一个对象

<Stack.Screen
    name="About"
    component={
    
    About}
    options={
    
    ({
     
      route }) => ({
    
     title: route.params.name })}
/>

这里 options是一个函数的时候,接受的参数,跟props里面增强的 是一样的,都有 navigationroute

在这里插入图片描述

更新 options,使用 setOptions

在这里插入图片描述

设置顶部的样式的一些配置属性

headerStyle: 对顶部盒子的样式设置

headerTintColor: 返回按钮title都是使用这个颜色

haederTitleStyle: 单独对title的样式设置

<Screen name="Home" 
        component={
    
    Home}
        options={
    
    {
    
    
            headerStyle:{
    
    backgroundColor: 'yellow'},
            headerTintColor: 'red',
            headerTitleAlign: 'center',
            headerTitleStyle: {
    
    
               fontWeight: 'bold'
            }
        }} />

在这里插入图片描述

在这里插入图片描述

针对多个路由都使用相同的样式,就可以写在 navigator组件上

<Navigator
      screenOptions={
    
    {
    
    
        headerStyle:{
    
    backgroundColor: 'yellow'},
        headerTintColor: 'red',
        headerTitleAlign: 'center',
        headerTitleStyle: {
    
    
           fontWeight: 'bold'
        }
      }}
    >
      <Screen
        name="Home"
        component={
    
    Home}
        options={
    
    {
    
     title: 'My home' }}
      />
	  <Screen
        name="About"
        component={
    
    About}
        options={
    
    {
    
     title: 'About' }}
      />
</Navigator>

其他的配置:

headerTitle: 设置title是一个渲染的组件

headerRight: 设置顶部右边的组件

headerLeft: 设置顶部左边的组件


6、嵌套路由

function Home() {
    
    
  return (
    <Tab.Navigator>
      <Tab.Screen name="Feed" component={
    
    Feed} />
      <Tab.Screen name="Messages" component={
    
    Messages} />
    </Tab.Navigator>
  );
}

function App() {
    
    
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen	
          name="Home"
          component={
    
    Home}
          options={
    
    {
    
     headerShown: false }}
        />
        <Stack.Screen name="Profile" component={
    
    Profile} />
        <Stack.Screen name="Settings" component={
    
    Settings} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

在这里插入图片描述

嵌套路由的结构


7、路由的生命周期

在这里插入图片描述

使用 navigate 方法跳转, A跳转到B ,那么 组件的componentDidMount会执行,当使用goBack()返回时,componentWillUnmount也会执行。

当然web端的生命周期来用于react-navigatioin, 肯定有着不同之处。

在这里插入图片描述

考虑一种情况,当进入A页面componentDidMount被执行,当A->B时(使用push()方法),BcomponentDidMount被执行,但是 A 页面是一致处于挂载中,所以componentWillUnmount是不会执行的。

B返回到A时, B的componentWillUnmount是会被执行的,但是A的componentDidMount 是不会执行的,因为A的页面是一直处于挂载的状态。

function App() {
    
    
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="First">
          {
    
    () => (
            <SettingsStack.Navigator>
              <SettingsStack.Screen
                name="Settings"
                component={
    
    SettingsScreen}
              />
              <SettingsStack.Screen name="Profile" component={
    
    ProfileScreen} />
            </SettingsStack.Navigator>
          )}
        </Tab.Screen>
        <Tab.Screen name="Second">
          {
    
    () => (
            <HomeStack.Navigator>
              <HomeStack.Screen name="Home" component={
    
    HomeScreen} />
              <HomeStack.Screen name="Details" component={
    
    DetailsScreen} />
            </HomeStack.Navigator>
          )}
        </Tab.Screen>
      </Tab.Navigator>
    </NavigationContainer>
  );
}

在这里插入图片描述

四个路由,被加载后,都会保存状态。

现在的目标就是: 想知道哪个组件处于活跃状态,然后单独做一些事情

1、监听 focus事件

function Profile({
     
      navigation }) {
    
    
  React.useEffect(() => {
    
    
    const unsubscribe = navigation.addListener('focus', () => {
    
    
      // Screen was focused
      // Do something
    });

    return unsubscribe;
  }, [navigation]);

  return <ProfileContent />;
}

2、使用钩子函数

import {
    
     useFocusEffect } from '@react-navigation/native';

function Profile() {
    
    
  useFocusEffect(
    React.useCallback(() => {
    
    
      // Do something when the screen is focused

      return () => {
    
    
        // Do something when the screen is unfocused
        // Useful for cleanup functions
      };
    }, [])
  );

  return <ProfileContent />;
}

Tab Navigation的实例

import * as React from 'react';
import {
    
     Button, Text, View } from 'react-native';
import {
    
     NavigationContainer } from '@react-navigation/native';
import {
    
     createNativeStackNavigator } from '@react-navigation/native-stack';
import {
    
     createBottomTabNavigator } from '@react-navigation/bottom-tabs';

function DetailsScreen() {
    
    
  return (
    <View style={
    
    {
    
     flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Details!</Text>
    </View>
  );
}

function HomeScreen({
     
      navigation }) {
    
    
  return (
    <View style={
    
    {
    
     flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Home screen</Text>
      <Button
        title="Go to Details"
        onPress={
    
    () => navigation.navigate('Details')}
      />
    </View>
  );
}

function SettingsScreen({
     
      navigation }) {
    
    
  return (
    <View style={
    
    {
    
     flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Settings screen</Text>
      <Button
        title="Go to Details"
        onPress={
    
    () => navigation.navigate('Details')}
      />
    </View>
  );
}

const HomeStack = createNativeStackNavigator();

function HomeStackScreen() {
    
    
  return (
    <HomeStack.Navigator>
      <HomeStack.Screen name="Home" component={
    
    HomeScreen} />
      <HomeStack.Screen name="Details" component={
    
    DetailsScreen} />
    </HomeStack.Navigator>
  );
}

const SettingsStack = createNativeStackNavigator();

function SettingsStackScreen() {
    
    
  return (
    <SettingsStack.Navigator>
      <SettingsStack.Screen name="Settings" component={
    
    SettingsScreen} />
      <SettingsStack.Screen name="Details" component={
    
    DetailsScreen} />
    </SettingsStack.Navigator>
  );
}

const Tab = createBottomTabNavigator();

export default function App() {
    
    
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={
    
    HomeStackScreen} />
        <Tab.Screen name="Settings" component={
    
    SettingsStackScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

设置图标

<Tab.Navigator
        screenOptions={
    
    ({
     
      route }) => ({
    
    
          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';
            }

            // You can return any component that you like here!
            return <Ionicons name={
    
    iconName} size={
    
    size} color={
    
    color} />;
          },
          tabBarActiveTintColor: 'tomato',
          tabBarInactiveTintColor: 'gray',
        })}
      >
</Tab.Navigation>

Drawer Navigation的实例

import * as React from 'react';
import {
    
     Button, View } from 'react-native';
import {
    
     createDrawerNavigator } from '@react-navigation/drawer';
import {
    
     NavigationContainer } from '@react-navigation/native';

function HomeScreen({
     
      navigation }) {
    
    
  return (
    <View style={
    
    {
    
     flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button
        onPress={
    
    () => navigation.navigate('Notifications')}
        title="Go to notifications"
      />
    </View>
  );
}

function NotificationsScreen({
     
      navigation }) {
    
    
  return (
    <View style={
    
    {
    
     flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button onPress={
    
    () => navigation.goBack()} title="Go back home" />
    </View>
  );
}

const Drawer = createDrawerNavigator();

export default function App() {
    
    
  return (
    <NavigationContainer>
      <Drawer.Navigator initialRouteName="Home">
        <Drawer.Screen name="Home" component={
    
    HomeScreen} />
        <Drawer.Screen name="Notifications" component={
    
    NotificationsScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}

总结

对花了一下午的时间,对react-navigation有着大体的认识,在开发过程中,感觉还是可以理解代码了。知识学不完,只有自己慢慢充实。

猜你喜欢

转载自blog.csdn.net/James_xyf/article/details/121194037