react-navigation
假期学习 React Native(简称RN),移动端没有像 Web 一样自带导航功能, react-navigation 是RN推荐的移动端导航工具。因 react-navigation 官网是英文网站,在此记录一下自己的学习过程和自己的理解。
安装
参考官网安装,需要额外安装配置的项目比较多,要特别注意。
开始
类型
导航有 stack navigator、tab navigator、drawer navigator 等几种。
- stack navigator 堆栈导航,顾名思义,页面会像堆栈一样可以压入、弹出
- tab navigator 标签导航,页面之间可以平行的切换,例如微信页脚的几个标签可以在【微信】【通讯录】【发现】【我】之间切换
- drawer navigator 抽屉导航,可以从屏幕的侧面划出的
思想
Screen & Navigator
使用 react-navigation 开发 APP 的主要思想是,我们可以独立开发每个页面(称为 Screen),然后,根据需要选择 react-navigation 中不同类型的导航,把页面组织起来(对应的是 Navigator)。
示例如下,导航将组织了两个页面 HomeScreen
和 DetailsScreen
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
route & navigation
react-navigation 给每个页面 (Screen) 传入了两个对象,可以通过 this.props.route
、this.props.navigation
调用。
route 主要是一些关于路由的信息
navigation 主要提供了一些页面跳转的方法
嵌套
另外,导航还可以嵌套,例如可以 stack navigator 作为 Screen 嵌入到 tab navigator。做的页面(Screen)多了,我们就希望将页面合理的组织起来,树形结构是一个不错的选择。使用嵌套导航,可以达到这个目的。
页面跳转
navigation.navigate('RouteName')
RouteName 可以是使用 React Navigation 定义的任意的 Screen name
navigation.goBack() 回退
- navigation.popToTop() 回退到第一个 Screen
等
传参
页面跳转时传参:navigation.navigate 与 navigation.push 可以传参,如
navigation.navigate('RouteName', {paramName: 'value'})
页面内部设置参数
navigation.setParams()
在 Screen 上可以设置初始参数
<Stack.Screen name="Details" component={Details} initialParams={{itemId:42}} />
接收参数
this.props.route.params?.itemId
自定义导航部件
stack navigation 默认提供一个头部(Header)(即在页面顶部显示Screen.name),而 tab navigation 默认提供一个底部标签栏,这些都是可以自定义的。
关于嵌套
机制
每个 Navigator 维护自己的导航历史
跳转(navigate)动作由其所在的 Nabigator 进行处理,如果无法处理,将冒泡到上一层的 Navigator 进行处理
(所以在跳转时可以不考虑导航的结构而直接写要跳转的页面名称)
每个 Navigator 的特定的跳转方法,可以被其子 Navigator 调用
注:stack navigator、tab navigator、drawer navigator 既有通用的跳转方法如
navigation.navigate
,也有每种 nabigator 自己特有的跳转方法。父Navigator的UI将显示在子Navigator之上,即子Nabigator是显示在父Nabigator之中的,即在界面上也显示出嵌套的效果。
注:如果共用 Header 或 Footer 时,可以考虑使用嵌套,否则就不要用嵌套。
嵌套中的跳转页面
// examples
navigation.navigate('Root');
navigation.navigate('Root', { screen: 'Settings' });
navigation.navigate('Root', {
screen: 'Settings',
params: { user: 'jane' },
});
navigation.navigate('Root', {
screen: 'Settings',
params: {
screen: 'Sound',
params: { screen: 'Media' },
},
});
嵌套的最佳实践
- 尽量减少嵌套,嵌套可能导致的问题:
- 编码困难
- 内存消耗、性能下降
- 用户体验差
- 嵌套的导航是实现一种界面设计的方法,而不是用来组织代码的方法。
生命周期
与 React 相关联的生命周期
假设在 stack navigator 中有,页面A,页面B。
进入页面A,调用
A.componentDidMount
- 进入页面B,调用
B.componentDidMount
- 离开页面B,调用
B.componentWillUnmount
离开页面A,调用
A.componentWillUnmount
React Navigation 生命周期的事件
focus
进入页面blur
离开页面
例子:
使用 addEventListener
function Profile({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// Screen was focused
// Do something
});
return unsubscribe;
}, [navigation]);
return <ProfileContent />;
}
使用 useFocusEffect
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 />;
}