如何从 stack.navigation 之外的组件使用 navigation.navigate

How to use navigation.navigate from a component outside the stack.navigation

我有一个使用 React native 的应用程序,我正在使用 react-navigation (5.2.9)。

我构建了一个 Stack.Navigator 屏幕,但我希望页脚组件位于外部,以便在所有屏幕中呈现。问题是,我无法从页脚导航,这是我需要做的,因为页脚有几个应该改变屏幕的按钮:

const Stack = createStackNavigator();

const App = () => {    
  return (
    <Provider store={store}>
      <NavigationContainer>
        <Header />
        <Stack.Navigator>
          <Stack.Screen
            name="Home"
            component={HomeScreen}
            options={{
            headerShown: false
          }}
          />
          <Stack.Screen
            name="Login"
            component={LoginScreen}
            options={{
            headerShown: false
          }}
          />
        </Stack.Navigator>
        <Footer />
      </NavigationContainer>
    </Provider>
  );
};

如何将导航道具传递给页脚组件?

来自文档。 https://reactnavigation.org/docs/connecting-navigation-prop/

import * as React from 'react';
import { Button } from 'react-native';
import { useNavigation } from '@react-navigation/native';

function GoToButton({ screenName }) {
  const navigation = useNavigation();

  return (
    <Button
      title={`Go to ${screenName}`}
      onPress={() => navigation.navigate(screenName)}
    />
  );
}

我最终构建了一个名为 screen 的组件,它只会包装屏幕的内容并根据道具呈现 header/footer:

import React from 'react';
import { View } from 'native-base';
import style from './style';
import Footer from '../../footer';
import Header from '../../header';

const Screen = ({
    footer,
    header,
    children,
    navigation
}) => (
  <View style={style.screen}>
    { header && <Header navigation={navigation} />}
    { children }
    { footer && <Footer navigation={navigation} />}
  </View>
);

export default Screen;

并像这样包装我的应用程序的屏幕:

<Screen header footer navigation={navigation}>
    ... screen content
</Screen>

如果我无法解决这个问题,我觉得这是最好的方法。

Stack.Screen 组件之外的组件不接收导航道具。所以在这种情况下,您必须在页脚组件中使用 refs 来获取 NavigationContainer,如下所示:

  1. 使用 const myRef = React.createRef()
  2. 创建一个 ref
  3. 将其传递给 <NavigationContainer ref={myRef}>,然后
  4. 使用该 ref 进行导航,myRef.current?.navigate(name, params)

都解释清楚了here。此处的文档将 ref 的创建分隔在一个新文件中,以允许您导入 ref 而不会出现依赖循环/问题。正如文档所述,您现在可以在任何 js 模块中调用 RootNavigation.navigate('ChatScreen', { userName: 'Lucy' });,而不仅仅是在 React 组件中。

虽然在你的情况下,你不需要单独文件中的引用。

const Stack = createStackNavigator();
const navigationRef = React.createRef();

const App = () => {    
  return (
    <Provider store={store}>
      <NavigationContainer ref={navigationRef}>
        <Header />
        <Stack.Navigator>
          <Stack.Screen
            name="Home"
            component={HomeScreen}
            options={{
            headerShown: false
          }}
          />
          <Stack.Screen
            name="Login"
            component={LoginScreen}
            options={{
            headerShown: false
          }}
          />
        </Stack.Navigator>
        <Footer navigationRef={navigationRef}/>
      </NavigationContainer>
    </Provider>
  );
};

并在 <Footer/> 中使用 navigationRef.current?.navigate(name, params)

试试这个:

创建一个名为:RootNavigation.js

的新文件
// RootNavigation.js

import * as React from 'react';

export const navigationRef = React.createRef();

export function navigate(name, params) {
  navigationRef.current?.navigate(name, params);
}
// file where you have the navigation

import {navigationRef} from './path/to/RootNavigation';

      <NavigationContainer ref={navigationRef}>
      .....
        <Footer />
      </NavigationContainer>

而Footer.js应该是这样的:

// Footer.js

import React from 'react';
import {View, Button} from 'react-native';
import * as RootNavigation from './path/to/RootNavigation';

const Footer= () => {
  return (
    <View>
      <Button
        title={'Go to'}
        onPress={() =>
          RootNavigation.navigate('screenName ', {userName: 'Lucy'})
        }
      />
    </View>
  );
};

export default Footer;

有关详细信息,您可以阅读文档。 https://reactnavigation.org/docs/navigating-without-navigation-prop/

screenOptions 中提取 navigation 的简单技巧。

function NavWrapper() {
  const navigatorRef = useRef<any>();
  <Tab.Navigator
    screenOptions={({ navigation: nav }) => navigatorRef.current = nav}
  >
    <Tab.Screen name="screen1" />
  </Tab.Navigator>
}

我使用 React 上下文通过全局状态解决了这个问题 API:

  // When enter in the HomeScreen:
  const { setGlobalNavigation, globalNavigation } = useGlobalContext();
  const navigation = useNavigation<RemindersNavigationProp>();

  useEffect(() => {
    if (setGlobalNavigation && !globalNavigation) setGlobalNavigation(navigation);
  }, [setGlobalNavigation, globalNavigation, navigation]);

  // When want to use:
  const { globalNavigation } = useGlobalContext();
  const handleNavigate = () => 
  globalNavigation.navigate("contactsStack", { screen: "newContact" });