React Navigation v5: как получить параметры маршрута родительского навигатора внутри дочернего экрана

Итак, у меня есть вложенные навигаторы

Главная Нижняя Вкладка Навигатор

  • Profile Bottom Tab # 1 (Stack.Navigator)
    • Profile View (Screen)
    • Последователи (экран)
    • Following (Top Tab.Navigator)
      • Pages (Screen)
      • Группы (экран)
  • Фид нижняя вкладка №2 (стопка)
  • Некоторые другие нижняя вкладка №3 (стопка)

Проблема заключается в том, что когда я перехожу с экрана просмотра профиля к следующему навигатору, я передаю некоторые параметры родительскому элементу Follow Navigator, и мне нужны все эти параметры на дочерних вкладках Screens (Pages / Groups).

Но маршрут дочерних экранов вкладок не получает параметры, которые передаются родительскому навигатору (следующий навигатор вкладок)

Есть ли способ сделать это?

Вот мой код: Стек профилей

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>

FollowTabs

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

Из экрана просмотра профиля я пытаюсь перейти к следующему экрану вкладок, и мне нужно передать некоторые параметры следующим образом.

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) Это еще не возможно?


person Ayesha Iftikhar    schedule 09.04.2020    source источник


Ответы (3)


В итоге я использовал React.Context, как рекомендовано в официальной документации по React Navigation . Пожалуйста, следуйте официальной документации для получения дополнительной информации.

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);
  ...
}
person Ayesha Iftikhar    schedule 10.04.2020

Итак, вот альтернативное хакерское решение без использования контекста; p

НО будьте осторожны, это решение обратного вызова рендеринга связано с затратами. Прочтите здесь

Примечание. По умолчанию React Navigation применяет оптимизацию к компонентам экрана, чтобы предотвратить ненужную визуализацию. Использование обратного вызова рендеринга удаляет эти оптимизации. Поэтому, если вы используете обратный вызов рендеринга, вам необходимо убедиться, что вы используете React.memo или React.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;
person Ayesha Iftikhar    schedule 25.06.2020

Редактировать !!! : Это работает только при первом переходе к дочернему объекту. Вероятно, есть способ каждый раз сбрасывать дочерний или родительский элемент, но, вероятно, лучше использовать контекст ...

Если кто-то все еще хочет неконтекстного решения, я считаю, что вы можете использовать опору 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>
);
person saetch_g    schedule 24.05.2021