react-navigation虽然一直在用,但始终没有将官网(英文版)给过一遍,最近要搭建一个新项目,对于导航嵌套有一定的要求,就借此机会将文档详细过了一下。阅读过程中发现很多想要的功能人家本身就支持,因为之前没有认真看文档,自己又造了一遍轮子而且还留下一些坑。下面我梳理一下比较常用但我之前没有注意到的那些API
navigate和push
navigation.navigate('RouteName'),如果指定路由在路由栈中存在,会回到该页面,否则会push到一个新页面;navigation.push('RouteName'),无论指定路由是否在路由栈中,都会新建一个路由页面并跳转过去。
疑问: A push B,B push C,C push D,D navigate A后,路由栈中还会存在BCD么
不会存在,经测试,navigate到哪个已存在的页面,该页面之后的路由都会被清空。下面附上两个case的结果
D navigate A后,路由栈中只剩A;D navigate B后,路由栈中只剩A、B
基于useNavigation可在任何能获取到navigation对象的地方触发导航操作,基于useRoute可以方便的获取到导航参数
基于NavigationContainer的ref属性,可以在无法访问到props的地方触发导航操作,比如:redux中间件
setParams更新参数
上个页面传过来的路由参数要做修改,直接通过setParams更改即可,不用再次新建一个state处理
疑问:setParams会触发render么
会,我将parmas的属性做为文本内容,点击按钮setParams后,文本内容更新
在路由的options配置中可使用params
路由的options即可以传对象也可以传函数,函数的入参有navigation和route

setOptions可更新路由配置
可以使用该API直接更新标题,另外当导航想要配置自定义的button组件时,也可以通过setOptions配置
可通过Stack.Navigator的screenOptions属性配置通用的options
跳转和传参
嵌套导航器
navigation.getParent显式侦听父事件
一个嵌套在选项卡导航器中的堆栈导航器,则堆栈导航器中的屏幕在使用时不会接收到由父选项卡导航器发出的事件,要从父导航器接收事件,可以通过如下方式:
const unsubscribe = navigation.getParent().addListener('tabPress', (e) => {
// Do something
});
useFocusEffect
页面显示时调用,传递的回调应该包裹在 React.useCallback 中,以避免过于频繁地调用
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 />;
}
useIsFocused,当前页面是否处于焦点状态
如果您使用的是选项卡或抽屉式导航器,因为导航器中的所有屏幕可能会同时渲染并保持渲染 - 这意味着StatusBar您设置的最后一个配置将被使用(可能在最后一个选项卡上您的标签导航器,而不是用户所看到的。为了解决这个问题,我们必须让状态栏组件知道屏幕焦点,并仅在屏幕获得焦点时渲染它。我们可以通过使用useIsFocused钩子并创建一个包装器组件来实现这一点:
import * as React from 'react';
import { StatusBar } from 'react-native';
import { useIsFocused } from '@react-navigation/native';
function FocusAwareStatusBar(props) {
const isFocused = useIsFocused();
return isFocused ? <StatusBar {...props} /> : null;
}
疑问:在该页面的子组件是否可以使用这两个API
可以,将这两个API放到子组件里,可以得到正确的结果
疑问:有useBlurEffet么
找了,没有,如果想要使用,使用使用如下订阅的方式
const unsubscribe = navigation.addListener('blur', () => {
// Screen was focused
// Do something
});
另外官方提供的页面生命周期只有focus和blur
基于不同的身份状态配置不同的路由栈,官方已经提供了成熟的设计方案,详细见文档
详情查看官方文档,下面四条是针对文档的简单总结
可以用两种方式来实现:
preventDefault在iOS上无效deep-linking
configuring-links
您可能希望将用户的位置保存在应用程序中,以便在应用程序重新启动后立即将其返回到同一位置。
这在开发过程中特别有价值,因为它允许开发人员在刷新应用程序时留在同一屏幕上。
具体操作见state-persistence
参数类型很尴尬,我是通过强转的手段实现的