React Navigation v5:如何在子屏幕内获取父导航器的路由参数

Posted

技术标签:

【中文标题】React Navigation v5:如何在子屏幕内获取父导航器的路由参数【英文标题】:React Navigation v5: How to get route params of the parent navigator inside the child screen 【发布时间】:2020-07-22 10:16:05 【问题描述】:

所以我有嵌套的导航器

主 BottomTab.Navigator

个人资料 底部标签 #1 (Stack.Navigator) 个人资料视图(屏幕) 关注者(屏幕) 以下(顶部选项卡导航器) 页面(屏幕) 组(屏幕) Feed 底部标签 #2(堆栈) 其他一些底部标签#3(堆栈)

问题是当我从 Profile View Screen 导航到 Follow Navigator 时,我将一些参数传递给父 Follow Navigator,并且我希望所有这些参数都在子选项卡屏幕(页面/组)中。

但是子选项卡屏幕的路由没有得到传递给父导航器(Following Tab Navigator)的参数

有没有办法做到这一点?

这是我的代码: 个人资料堆栈

const ProfileStack = () => (
  <Stack.Navigator
    initialRouteName='profileView'
  >
    <Stack.Screen
      name='profileView'
      component=ProfileScreen
      options=
        headerMode: 'screen',
        headerShown: false,
      
    />

    <Stack.Screen
      name='followers'
      component=FollowersScreen
      options=
        headerTitle: 'Followers',
      
    />
    <Stack.Screen
      name='following'
      component=FollowingTabs
      options=
        headerTitle: 'Following',
      
    />
 </Stack.Navigator>

FollowingTabs

const Tabs = createMaterialTopTabNavigator();
export const FollowingTabs = () => (
  <Tabs.Navigator
    initialRouteName='page'
    lazy
    swipeEnabled
  >
    <Tabs.Screen
      component=PageScreen
      name='page'
      options= tabBarLabel: '2 Pages' 
    />
    <Tabs.Screen
      component=GroupScreen
      name='groups'
      options= tabBarLabel: '3 Groups' 
    />
  </Tabs.Navigator>
);

从 profileView 屏幕我试图导航到以下选项卡屏幕,需要传递一些参数,如下所示。

const onPressHandler = () => 
    navigation.navigate('following', ** isPublicProfile, firstName **);  // These parameters are passed to route of the following Tabs Navigator
  ;

当我尝试在子选项卡(页面/组)中读取这些参数时,这些参数是未定义的

const PageScreen = ( route ) => 
  const  isPublicProfile, firstName  = route.params; // undefined?? Cant read parent's params
...

任何帮助将不胜感激。

编辑:我在 github (https://github.com/react-navigation/rfcs/issues/43) 上发现了这个未解决的问题,这还不可能吗?

【问题讨论】:

【参考方案1】:

所以我最终按照官方 React Navigation documentation 的推荐使用了 React.Context。更多信息请关注官方文档。

1- 使用 React 上下文并使用上下文提供程序包装导航器以将数据传递到屏幕(推荐)。

这是我的解决方案:

const DEFAULT_CONTEXT = 
  isPublicProfile: false,
  ...
;

const FollowingTabNavigatorContext = createContext(DEFAULT_CONTEXT);

在父标签导航器中

const Tabs = createMaterialTopTabNavigator();

export const FollowingTabs = ( route ) => 
  const  isPublicProfile  = route.params;
  return (
    <FollowingTabNavigatorContext.Provider value= isPublicProfile >
      <Tabs.Navigator
        initialRouteName='pages'
        lazy
        swipeEnabled
      >
        <Tabs.Screen
          component=PageScreen
          name='pages'
          options= tabBarLabel: '2 Pages' 
        />
        <Tabs.Screen
          component=GroupScreen
          name='groups'
          options= tabBarLabel: '3 Groups' 
        />
      </Tabs.Navigator>
    </FollowingTabNavigatorContext.Provider>
  );
;

FollowingTabs.propTypes = propTypes;
FollowingTabs.defaultProps = defaultProps;

最后在我的子标签屏幕中:

export const GroupScreen = () => 
  const  isPublicProfile  = useContext(FollowingTabNavigatorContext);
  ...

【讨论】:

【参考方案2】:

所以这是一个不使用上下文的替代 hacky 解决方案;p

但请注意,此渲染回调解决方案是有代价的。阅读here

注意:默认情况下,React Navigation 会对屏幕组件进行优化,以防止不必要的渲染。使用渲染回调会删除这些优化。因此,如果您使用渲染回调,您需要确保为屏幕组件使用React.memoReact.PureComponent,以避免出现性能问题。

const Tabs = createMaterialTopTabNavigator();

export const FollowingTabs = ( route ) => 
  const  isPublicProfile  = route.params;
  return (
      <Tabs.Navigator
        initialRouteName='pages'
        lazy
        swipeEnabled
      >
        <Tabs.Screen
          name='pages'
          options= tabBarLabel: '2 Pages' 
        >
          () => <PageScreen isPublicProfile=isPublicProfile />
        </Tabs.Screen>
        <Tabs.Screen
          name='groups'
          options= tabBarLabel: '3 Groups' 
        >
         () => <GroupScreen isPublicProfile=isPublicProfile />
        </Tabs.Screen>
      </Tabs.Navigator>
  );
;

FollowingTabs.propTypes = propTypes;
FollowingTabs.defaultProps = defaultProps;

【讨论】:

【参考方案3】:

编辑!!! :这仅在您第一次导航到子对象时有效。可能有一种方法可以每次都重置孩子或父母,但使用上下文可能更好......

如果有人仍然想要一个非上下文解决方案,我相信您可以使用孩子们中的initialParams 道具来做您正在寻找的事情。

假设路由有一些参数传递给它。

export const FollowingTabs = (route) => (
  <Tabs.Navigator
    initialRouteName='page'
    lazy
    swipeEnabled
  >
    <Tabs.Screen
      component=PageScreen
      name='page'
      options= tabBarLabel: '2 Pages' 
      initialParams=route.params // Then you can grab these params using the usual route.params in the PageScreen component 
    />
    <Tabs.Screen
      component=GroupScreen
      name='groups'
      options= tabBarLabel: '3 Groups' 
    />
  </Tabs.Navigator>
);

【讨论】:

【参考方案4】:

您可以轻松地在选项卡导航器中使用 initialParams 并传递道具。 检查此解决方案。

<Stack.Screen name="Settings" >
     (props) => (
      <Tab.Navigator>
        <Tab.Screen name="Tab1" component= Tab1  
          initialParams= props.route.params   // <- pass params from root navigator
        />
        <Tab.Screen name="Tab2" component= Tab2  
          initialParams= props.route.params  
        />
      </Tab.Navigator>
      )
  </Stack.Screen>

参考 https://github.com/react-navigation/rfcs/issues/43#issuecomment-610706264

【讨论】:

以上是关于React Navigation v5:如何在子屏幕内获取父导航器的路由参数的主要内容,如果未能解决你的问题,请参考以下文章

如何重置嵌套的堆栈导航导航器 react-navigation v5

将 React Navigation v4 深层链接配置迁移到 React Navigation v5 时遇到问题

是否可以使用 react-navigation (v5) 以 UIModalPresentationPageSheet 或 UIModalPresentationFormSheet 样式呈现模式?

React Navigation V5 隐藏底部选项卡

最新版 react-navigation v5.0 上带有标题按钮的换屏

react-navigation v5 中的 Typescript StackNavigatonProps 和 Screen 道具