React Native 入门 3 - Navigation

React Native 入门 3 - Navigation

这一段主要讲一些关于 Navigation 的用处,Navigation 有点类似于网页的导航,起到在 app 中切换页面的用途,使用的包为 React NavigationReact Navigation 是一个功能很强大的库,常用的导航功能都有包含,可以搭配 expo 使用 (推荐) 也可以单独与 react native 一起使用。

这里会简单介绍一下 Stack(点击页面中的组件进行跳转)和 Drawer(菜单栏,类似于网页开发的 hamburger)。

Demo 如下:

React Native Demo2

Stack

使用 Stack 之前需要安装一些依赖包:

> npm install @react-navigation/stack
> npx expo install react-native-gesture-handler

基本配置

基本配置方法如下:

  • App.js

    import { NavigationContainer } from '@react-navigation/native';
    import { createNativeStackNavigator } from '@react-navigation/native-stack';
    
    const Stack = createNativeStackNavigator();
    
    export default function App() {
      return (
        <>
          <NavigationContainer>
            <Stack.Navigator>
              <Stack.Screen
                name="MealsOverview"
                component={MealsOverviewScreen}
                options={{}}
              />
            </Stack.Navigator>
          </NavigationContainer>
        </>
      );
    }
    
  • Screen

    const MealsOverviewScreen = ({ route, navigation }) => {
      // implemented jsx here
      return <View></View>;
    };
    

直接挂载在 Stack.Screen 下的组件可以从 props 中获取 navigation, route, options, back 等一些 attributes,这些可以直接在 Stack.Screen 中的 options 中设置,也可以在组件内动态设置。

如果当前组件不是直接挂在于 Stack.Screen 下,class based component 暂时还没有怎么了解怎么配置,FP 可以使用对应的 useHook 进行调用,如:const route = useRoute<ProfileScreenRouteProp>();

其中 navigation 可以用于设置与当前组件相关的内容,如设置当前页面的标题,跳转页面等。

route 管理路由相关的部分,如传一些值(类比于 react-router 动态传 id、query param 之类的参数),

页面跳转案例

一个简单的案例为,从首页点击某个子类进去后,子类需要显示对应子类的标题:

在这里插入图片描述

在这里插入图片描述

那么这里需要完成两个步骤:

  1. 通过主页进行导航的时候传值到子组件——可以是 title 也可以是 id

    const pressHandler = () => {
      navigation.navigate('MealsOverview', {
        categoryId: item.id,
      });
    };
    

    注意 ⚠️:navigation.navigate() 的第一个参数必须要和 Stack.Screen 中的 name 一致。

  2. 子组件通过 navigation 进行动态配置

    categoryTitle = () => {};
    
    useLayoutEffect(() => {
      navigation.setOptions({
        title: categoryTitle,
      });
    }, [categoryId, navigation]);
    

    这里使用 useLayoutEffect 去尽可能地提升性能。

这样页面中的跳转就基本实现了。

样式配置

每个挂载于 Stack.Screen 的页面都可以通过 headerStylecontentStyle 进行样式的配置,不过这样配置的样式只会在当前页面进行应用,如果想要设置一个 base tone,可以在 Stack.Navigator 中通过 screenOptions 设置:

<Stack.Navigator
  screenOptions={{
    title: 'All Categories',
    headerStyle: { backgroundColor: '#351401' },
    headerTintColor: 'white',
    contentStyle: { backgroundColor: '#3f2f25' },
  }}
></Stack.Navigator>

Drawer

使用 Drawer 同样也需要下载一些额外的依赖包:

npm install @react-navigation/drawer
npx expo install react-native-gesture-handler react-native-reanimated

另外我也遇到了一点运行上的问题,解决方案参考: React Native error: Export namespace should be first transformed by `@babel/plugin-proposal-export-namespace-from,步骤为:

  1. 安装 npm install react-native-reanimated

  2. 更新 babel.config.js:

    module.exports = function (api) {
      api.cache(true);
      return {
        presets: ['babel-preset-expo'],
        // add this
        plugins: ['react-native-reanimated/plugin'],
      };
    };
    
  3. 重新运行项目并清理 cache: npm start --clear

如果单独使用 Drawer,那么基本配置和 Stack 没有什么区别。不过这个案例会使用 Stack 嵌套 Drawer 的用法,因此会稍作一些修改:

  • app.js

    import { StatusBar } from 'expo-status-bar';
    import { StyleSheet } from 'react-native';
    import { NavigationContainer } from '@react-navigation/native';
    import { createDrawerNavigator } from '@react-navigation/drawer';
    import { createNativeStackNavigator } from '@react-navigation/native-stack';
    import { Ionicons } from '@expo/vector-icons';
    
    const Stack = createNativeStackNavigator();
    const Drawer = createDrawerNavigator();
    
    const DrawerNavigator = () => {
      return (
        <Drawer.Navigator useLegacyImplementation={true}>
          <Drawer.Screen
            name="Categories"
            component={CategoriesScreen}
            options={{
              title: 'All Categories',
              drawerIcon: ({ color, size }) => (
                <Ionicons color={color} size={size} name="list" />
              ),
            }}
          />
        </Drawer.Navigator>
      );
    };
    
    export default function App() {
      return (
        <>
          <StatusBar style="dark" />
          <NavigationContainer>
            <Stack.Navigator>
              <Stack.Screen
                name="DrawerScreens"
                component={DrawerNavigator}
                options={{
                  headerShown: false,
                }}
              />
              <Stack.Screen
                name="MealsOverview"
                component={MealsOverviewScreen}
              />
              <Stack.Screen
                name="MealDetails"
                component={MealDetailScreen}
                options={{
                  title: 'About The Meal',
                }}
              />
            </Stack.Navigator>
          </NavigationContainer>
        </>
      );
    }
    

    Drawer 的配置和 Stack 基本一致,这里主要的变化就是将 Stack 的 header 进行隐藏,否则就会出现两个 header。

    另一个变化是 useLegacyImplementation={true},这个可能跟版本有关,目前我使用的版本 "@react-navigation/drawer": "^6.6.2",如果不添加这个选项则会报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值