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

React Navigation v5: How to get route params of the parent navigator inside the child screen

所以我有嵌套的导航器

主要BottomTab.Navigator

问题是当我从 Profile View Screen 导航到 Following Navigator 时,我将一些参数传递给父级 Following Navigator,并且我想要子选项卡屏幕中的所有这些参数 (Pages/Groups)。

但是子选项卡屏幕的路由没有获取传递给父导航器(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>

以下选项卡

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
  };

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

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

如有任何帮助,我们将不胜感激。

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

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

1- Use React context and wrap the navigator with a context provider to pass data to the screens (recommended).

这是我的解决方案:

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);
  ...
}

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

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

Note: By default, React Navigation applies optimizations to screen components to prevent unnecessary renders. Using a render callback removes those optimizations. So if you use a render callback, you'll need to ensure that you use React.memo or React.PureComponent for your screen components to avoid performance issues.

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;

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

如果有人仍然想要 non-context 解决方案,我相信您可以使用 children 中的 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>
);

您可以轻松地在选项卡导航器中使用 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