Skip to content

参数传递和标题栏信息配置

本小节我们来看两个内容:

参数传递#

参数传递在导航中是一个非常重要的内容,例如点击电影进入到这一部电影的电影详情,那么我们就需要传递一个 id 过去。

参数传递整体分为两步:

navigation.navigate('RouteName', {
/* params go here */
})
route.params

来看一个官方提供的示例:

function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => {
/* 1. Navigate to the Details route with params */
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
})
}}
/>
</View>
)
}
function DetailsScreen({ route, navigation }) {
/* 2. Get the param */
const { itemId, otherParam } = route.params
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Text>itemId: {JSON.stringify(itemId)}</Text>
<Text>otherParam: {JSON.stringify(otherParam)}</Text>
<Button
title="Go to Details... again"
onPress={() =>
navigation.push('Details', {
itemId: Math.floor(Math.random() * 100),
})
}
/>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
)
}

第二屏不仅可以接收第一屏传递过来的参数,还可以手动修改这个参数,例如:

<Button
title="修改参数"
onPress={() => {
navigation.setParams({
otherParam: 'someText',
})
}}
/>

在上面的代码中,我们在 DetailsScreen 这一屏所返回的 JSX 中,添加了一个 Button 组件,点击之后通过 navigation.setParams 重新设置接收到的 otherParam 参数。

可以在 Stack.Screen 中通过 initialParams 属性设置参数的默认值,例如:

<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ itemId: 42 }}
/>

设置之后,我们在 Home 这一屏中,跳转到 DetailsScreen 时,即使不传递 itemId 参数,DetailsScreen 这一屏也能接收到一个名为 itemId 的参数。

有些时候,我们并不是只会将第一屏的数据传递给第二屏,可能刚好相反要将第二屏的数据反向传递给第一屏,使用 navigate 方法的时候,也可以很轻松的向上一屏传递数据。例如:

import * as React from 'react'
import { Text, TextInput, View, Button } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen({ navigation, route }) {
React.useEffect(() => {
if (route.params?.post) {
// Post updated, do something with `route.params.post`
// For example, send the post to the server
}
}, [route.params?.post])
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Create post"
onPress={() => navigation.navigate('CreatePost')}
/>
<Text style={{ margin: 10 }}>Post: {route.params?.post}</Text>
</View>
)
}
function CreatePostScreen({ navigation, route }) {
const [postText, setPostText] = React.useState('')
return (
<>
<TextInput
multiline
placeholder="What's on your mind?"
style={{ height: 200, padding: 10, backgroundColor: 'white' }}
value={postText}
onChangeText={setPostText}
/>
<Button
title="Done"
onPress={() => {
// Pass and merge params back to home screen
navigation.navigate({
name: 'Home',
params: { post: postText },
merge: true,
})
}}
/>
</>
)
}
const Stack = createNativeStackNavigator()
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator mode="modal">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="CreatePost" component={CreatePostScreen} />
</Stack.Navigator>
</NavigationContainer>
)
}

标题栏信息配置#

Screen 组件接受 options 属性,它可以是对象,也可以是返回对象的函数,其中包含各种配置选项。 例如上面我们所写的:

<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Overview' }}
/>

有些时候标题栏并不是一开始就固定的,而是通过上一屏跳转过来时传递的参数过来而决定的。例如:

import * as React from 'react'
import { View, Text, Button } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Profile"
onPress={() =>
navigation.navigate('Profile', { name: 'Custom profile header' })
}
/>
</View>
)
}
function ProfileScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Profile screen</Text>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
)
}
const Stack = createNativeStackNavigator()
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'My home' }}
/>
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={({ route }) => ({ title: route.params.name })}
/>
</Stack.Navigator>
</NavigationContainer>
)
}
export default App

在标题栏内容已经确定的当前屏幕下,想要修改当前屏的标题,可以使用 navigation.setOptions,来看下面的例子:

import * as React from 'react'
import { View, Text, Button } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Update the title"
onPress={() => navigation.setOptions({ title: 'Updated!' })}
/>
</View>
)
}
const Stack = createNativeStackNavigator()
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'My home' }}
/>
</Stack.Navigator>
</NavigationContainer>
)
}
export default App

我们可以自定义标题的样式。自定义标题样式时要使用三个关键属性:headerStyle、headerTintColorheaderTitleStyle

例如:

import * as React from 'react'
import { View, Text } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
)
}
const Stack = createNativeStackNavigator()
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: 'My home',
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
}}
/>
</Stack.Navigator>
</NavigationContainer>
)
}
export default App

一个很常见的需求,就是将整个应用的标题栏样式统一成一个样式。可以通过配置 screenOptions 来实现这个功能。如下:

// In App.js in a new project
import * as React from 'react'
import { View, Text, Button } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
)
}
function DetailsScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
)
}
const Stack = createNativeStackNavigator()
function App() {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Overview' }}
/>
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
)
}
export default App

有时,我们需要的不仅仅是更改标题的文本和样式,还需要更多的控制。

例如,我们可能想要渲染图像来代替标题,或者将标题变成一个按钮。在这些情况下,可以完全覆盖用于标题的组件并提供我们自己的组件。例如:

import * as React from 'react'
import { View, Text, Image } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
)
}
function LogoTitle() {
return (
<Image
style={{ width: 30, height: 30 }}
source={require('./images/logo.jpg')}
/>
)
}
const Stack = createNativeStackNavigator()
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ headerTitle: (props) => <LogoTitle {...props} /> }}
/>
</Stack.Navigator>
</NavigationContainer>
)
}
export default App