结合 React Router 看 React Navigation

·  阅读 1616

1 前言

RN 菜鸟一枚,才开始入手,所以该文章适合新手或者基础开发者观看,希望能对你有所帮助。

在使用 React 开发 web 端页面时,会使用 React Router 进行路由管理,那么在 React Native 中,怎么进行路由管理呢?答案就是 React Navigation。 首先第一点,个人觉得它的 api 设计就非常棒。

2 安装

yarn add @react-navigation/native 
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view 

复制代码

3 必须掌握的基本概念

想要学废 React Navigation,必须要掌握以下几个点。

3.1 Screen - 官方文档

React Native 中有很多的 Screen,概念类似于 React Router 中的 Route,将路由和 Component 进行联系起来。

// React Router 
<Route path="/login" component={LoginComponent} /> 
// React navigation 
<Stack.Screen name="Login" component={LoginScreen} />
复制代码

3.2 Navigators - 官方文档

Navigators 允许你定义项目的导航结构,还支持很多配置,比如headers、tab bars等. 它类似于 React Router 中里面的 Router,一个 Router可以理解为需要负责一组 Route 的相互跳转。同理,一个 Navigators 也需要负责一组 Screen 的相互跳转,在实际使用的时候,React Navigation 做了一层封装,将常用的几种布局封装成了不同的 Navigator。

3.2.1 Stack Navigator - 官方文档

Stack Navigator 基本等同于 Router + Switch,每次切换整个页面都会切换

// React Router 对等实现 
<Suspense fallback={<LoadableLoading />}>
  <Router history={history}>
      <Switch>
        <Route path="/login" component={Login} />
      </Switch>
  </Router>
</Suspense>
  
// React Navigation Stack Navigator
<RootSiblingParent>
  <Provider store={store}>
    <SafeAreaView style={styles.container}>
        <NavigationContainer>
            <Stack.Navigator initialRouteName='logged'>
                <Stack.Screen name='Login' component={LoginScreen} options={{ headerShown: false }} />
            <<Stack.Navigator/>
       </NavigationContainer>
    </SafeAreaView>
  </Provider>
</RootSiblingParent>

复制代码

3.2.2 Drawer Navigator - 官方文档

Drawer Navigation 类似于在 Router + Switch 的基础上额外增加了一个 Drawer 组件,这个组件放在父组件,会在访问每个子路由的时候都会展示。

// React Route
 <Router>
    <Route name="/" component={DrawerComponent} />
    <Switch>
      <Route name="/home" component={HomeComponent} />
      <Route name="/ddd" component={DddComponent} />
    </Switch>
  </Router>
  
 //Drawer Navigator
<NavigationContainer>
    <Drawer.Navigator>
      <Drawer.Screen name="Home" component={HomeScreen} />
      <Drawer.Screen name="Notifications" component={NotificationsScreen} />
    </Drawer.Navigator>
</NavigationContainer>

复制代码

3.2.3 Bottoms Tab Navigator - 官方文档

Drawer Navigator 类似于在 Router + Switch 的基础上额外增加了一个底部 Tab 组件,这个组件放在父组件,会在访问每个子路由的时候都会展示

 //Drawer Navigator
 import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

const Tab = createBottomTabNavigator();
<NavigationContainer>
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="ddd" component={DddScreen} />
    </Tab.Navigator>
</NavigationContainer>
复制代码

3.2.4 Material Bottoms Tab Navigator - 官方文档

Drawer Navigator 类似于在 Router + Switch 的基础上额外增加了一个底部 Tab 组件,这个组件放在父组件,会在访问每个子路由的时候都会展示

 //Drawer Navigator
 import { createMaterialBottomTabNavigator } from '@react-navigation/bottom-tabs';

const Tab = createMaterialBottomTabNavigator();
<NavigationContainer>
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="ddd" component={DddScreen} />
    </Tab.Navigator>
</NavigationContainer>
复制代码

3.3 跳转和页面栈

和浏览器类似,Native 也是用栈来保存访问历史记录, 但是不同与浏览器只有入栈一个页面,出栈一个页面两种操作,Native 提供了更多的对页面栈的操作接口,React Navigation 在此之上做封装成了几个 API。

3.3.1 navigation.navigate(screen) 入栈新页面

  • 如果当前已经是这个 Screen,则不会跳转

  • 如果页面栈内已经有这个 Screen,则将这个 Screen 上的所有 Screen 出栈

3.3.2 navigation.push(screen) 入栈新页面

注意:如果当前已经是这个 Screen,则栈内会有两个同样的 Screen

3.3.3 navigation.replace(screen) 替换当前页面(待支付到支付完成页面 后退不需要到待支付就可以用这个

3.3.4 navigation.goback(screen) 后退一页 关闭当前页

3.3.5 navigation.pop() 默认返回到上一页

3.3.6 navigation.popToTop() 返回至最顶层页面

  • 去到第一个页面 - 即只保留页面栈最底层页面,将其余所有页面出栈

4 页面生命周期和 useHooks(很重要)

我只会列举一下常用的 hooks,感兴趣的可以去官网查看更多。 在web 环境中,我们一般就关注三个生命周期,

  • mount:页面创建
  • update:页面更新
  • destroy:页面销毁或者注销 对于 Native 环境来说,除了上面的之外,需要额外关心的两个页面生命周期
  • App 切到后台
  • App 切回前台

4.1 addListener - 官方文档

const unsubscribe = navigation.addListener('tabPress', (e) => {
  // Prevent default action
  e.preventDefault();
});
function Profile({ navigation }) {
  React.useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      // do something
    });
    return unsubscribe;
  }, [navigation]);
  return <ProfileContent />;
}

复制代码
  • focus - 当屏幕成为焦点时,会发出这个事件

  • blur - 当屏幕失焦时会发出这个事件

  • beforeRemove -当用户离开屏幕时, 防止用户离开

  • state (advanced) - (高级)-当导航器的状态改变时发出此事件

  • tabPress (advanced) - 监听 tab 页切换

4.2 useFocusEffect - 官方文档

对此 React Navigation 封装了 useFocusEffect,采用了类似 useEffect 的设计

import { useFocusEffect } from '@react-navigation/native';
function Profile({ userId }) {
const [user, setUser] = React.useState(null);
useFocusEffect(
    React.useCallback(() => {
        const unsubscribe = API.subscribe(userId, user => setUser(user));
        return () => unsubscribe();
        }, [userId])

    );
    return <ProfileContent user={user} />;
}
复制代码

4.3 useIsFocused - 官方文档

判断当前页面的焦点状态

注意: 这个 hook 会触发页面 re-renders,如果你的页面组件很多,建议使用 React.useMemo 或者 React.PureCompnent 来减少 re-renders。

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

function Profile() {
const isFocused = useIsFocused();
return <Text>{isFocused ? 'focused' : 'unfocused'}</Text>;
}
复制代码

4.4 useNavigation - 官方文档

这个hook 类似于 React Router 中的 useHistory 函数,useNavigation 可以访问 navigation 对象。当你不想使用一直传递 navigation 时,就可以使用这个方法。

import * as React from 'react';
import { Button } from 'react-native';
import { useNavigation } from '@react-navigation/native';
function MyBackButton() {
    const navigation = useNavigation();
    return (
        <Button
        title="Back"
        onPress={() => {
            navigation.goBack();
            }}
        />
    );
}
复制代码

4.5 useRoute - 官方文档

它可以用来获取 route 参数中的 object,类似于 React Router 中的 useLocation,

import * as React from 'react';
import { Text } from 'react-native';
import { useRoute } from '@react-navigation/native';

function MyText() {
  const route = useRoute();

  return <Text>{route.params.caption}</Text>;
}

复制代码

常用页面层级架构

我们一般 app 常用的页面一般是 Login、LoggedScreen、Setting 简单层级图如下:

image.png

我们再来结合一下 Sreen 和 Navgation 画一下

image.png

最后

React Router 和 React Navigation 都是一个了不起的库,它可以在一个页面模拟出中多页面的情况,并具有很高的可用性。

分类:
前端
收藏成功!
已添加到「」, 点击更改