React-Navigation基础知识
React Navigation在App中创建导航结构
Web浏览器中,可以通过a链接到不同的页面,当用户按下后退按钮,浏览器从访问记录堆栈中弹出项目
RN无法像浏览器一样管理访问路由,需要通过React Navigation实现
React Navigation的本机堆栈导航器为App提供一种在屏幕之间转换和管理导航历史记录的方法
Android上,React Navigation挂钩到硬件后退出,并goBack()在用户按下它时触发该功能
将参数传递给路由
- 通过该参数放入对象中作为函数的第二个参数传递给路由 navigation.navigate: navigation.navigate('RouteName',
- 读取屏幕组件中的参数:route.params
Note: 传递的参数是JSON可序列化的,这样可以使用状态持久性,并且屏幕组件将具有用于实现深度链接的正确契约
<Button color="success" onPress={() => {
navigation.navigate(
'Details',
{
itemId: 86,
otherParam: 'anything you want here!'
}
)
}}>
初始参数
可以将一些初始参数传递到屏幕,在导航到此屏幕上未指定任何参数时生效
在prop上指定initialParams
<Stack.Screen
name='Details'
component={DetailScreen}
initialParams={{ itemId: 42 }}
/>
参数回传
navigation.navigate({
name: 'Home',
params: { post: postText },
merge: true
});
参数内容规范
- 错误案例(反模式)
// Don't do this
navigation.navigate('Profile', {
user: {
id: 'jame',
firstName: 'Jane',
lastName: 'Done',
age: 25,
}
});
这是一种反模式,可以能会导致显示过时数据
更好的方法是参数中仅仅传递用户ID
navigation.navigate('Profile', {userId: '80a808sda808ds0812'}
规范案例
1. ID, eg: 用户ID、项目ID等,eg: navigation.navigate('Profile', { userId: 'Jane'})
2. 当存在一个项目列表的时候,用于排序、过滤数据等的参数, eg: navigation.navigate('Feeds',{ sortBy: 'latest'})
3. 时间戳、页码或分页光标, eg: navigation.navigate('Chat', { beforeTime: 435612089})
4. 用于填充屏幕上输出以组成某些内容的数据, eg: navigation.navigate('ComposeTweet', {title: 'Hello World!'})
★ 将App数据和导航状态分开
传递给函数的参数options是具有一下属性的对象:
- navigation - 屏幕的导航道具
- route - 屏幕的路线道具
更新 options setOptions
/* Inside of render() of React class */
<Button
title='Update the title'
onPress={() => navigation.setOptions({ title: 'Updated!'})}
/>
调整标题
自定义标题样式需要使用三个关键属性:headerStyle、headerTintColor和headerTitleStyle
- headerStyle: 将应用于View包装标题样式对象
- headerTintColor: 后退按钮和标题都使用此属性作为颜色,
- headerTitleStyle: 自定义标题样式 fontFamily、fontWeight等样式Text属性
function StackScreen() {
return (
<Stack.Navigator
name='Home'
component={HomeScreen}
options={{
title: 'My Home',
headerStyle: {
backgroundColor: '#3ab09e'
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}
>
</Stack.Navigator>
)
}
实现options在多个screen页面共享
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'My home' }}
/>
</Stack.Navigator>
headerTitle提供组件而不是title那样?headerTitle是一个特定于标题的属性而title将用于选项卡栏、抽屉等
默认headerTitle为Text显示title
headerRight 使用带有处理程序的按钮来更新onPress,该处理程序可以访问组件的状态并可以更新它
嵌套导航器
嵌套导航器意味着在另一个导航器的屏幕内渲染另一个导航器
function Home() {
return (
<Tab.Navigator>
<Tab.Screen name='Feed' component={Feed}/>
<Tab.Screen name='Message' component={Message}/>
</Tab.Navigator>
)
}
function App() {
return (
<NavigationContainer>
<Stack.Navigation>
<Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false}}
/>
<Stack.Screen name="Profile" component={Profile}/>
<Stack.Screen name="Settings" component={Setting}/>
</Stack.Navigator>
</NavigationContainer>
)
}
* Stack.Navigator
- Home(Tab.Navigator)
- Feed(Screen)
- Message(Screen)
- Profile(Screen)
- Settings(Screen)
嵌套导航的最佳实践
将嵌套导航器减少到最少,尽可能少的嵌套来实现想要的行为
- 可能会导致深度嵌套的视图层次结构,可能会导致低端设备中的内存和性能问题
- 嵌套相同类型的导航器(eg: 选项卡、抽屉)导致用户体验混乱
- 如果嵌套太多,当导航到嵌套屏幕、配置深层链接的时候,代码会变得难以理解
将嵌套导航器视为实现所需的UI的一种方式,而不是组织代码的一种方式
<Stack.Navigator>
{ isLoggedIn ? (
// Screens for logged in users
<Stack.Group>
<Stack.Screen name="Home" component={Home}/>
<Stack.Screen name="Profile" component={Profile}/>
</Stack.Group>
) : (
// Auth screens
<Stack.Group screenOptions={{ headerShown: false }}>
<Stack.Screen name="SignIn" component={SignIn}/>
<Stack.Screen name="SignUp" component={SignUp}/>
</Stack.Group>
) }
{/* Common modal screens */}
<Stack.Group screenOptions={{ presentation: 'modal'}}>
<Stack.Screen name="Help" component={Help}/>
<Stack.Screen name="Invite" component={Invite}/>
</Stack.Group>
</Stack.Navigator>
导航生命周期
使用一个具有两个屏幕(Home和Details)的堆栈导航器并学习如何使用navigation.navigate('RouteName')在路线之间导航
可以通过监听focus和blur事件分别了解屏幕何时进入焦点或失焦
function Profile({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// Screen was focused
// Do sth...
});
}, [navigation]);
return <ProfileContent/>
}
useFocusEffect可使用钩子来执行副作用,而不是手动添加事件监听器,就像React的useEffect钩子
它和导航生命周期相关
import { useFocusEffect } from '@react-navigation/native';
function Profile() {
useFocusEffect(
React.useCallback(() => {
// Do sth when the screen is focused
// Useful for cleanup functions
}, [])
);
return <ProfileContent/>;
}
根据屏幕是否聚焦来渲染不同的内容,可以使用useIsFocused返回一个布尔值来指示屏幕是否聚焦的钩子