React-Navigation基础知识

React Navigation在App中创建导航结构
Web浏览器中,可以通过a链接到不同的页面,当用户按下后退按钮,浏览器从访问记录堆栈中弹出项目
RN无法像浏览器一样管理访问路由,需要通过React Navigation实现
React Navigation的本机堆栈导航器为App提供一种在屏幕之间转换和管理导航历史记录的方法
Android上,React Navigation挂钩到硬件后退出,并goBack()在用户按下它时触发该功能

将参数传递给路由

  1. 通过该参数放入对象中作为函数的第二个参数传递给路由 navigation.navigate: navigation.navigate('RouteName',
  2. 读取屏幕组件中的参数: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是具有一下属性的对象:

  1. navigation - 屏幕的导航道具
  2. 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返回一个布尔值来指示屏幕是否聚焦的钩子

posted @ 2024-01-29 15:27  Felix_Openmind  阅读(174)  评论(0编辑  收藏  举报