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

Posted

技术标签:

【中文标题】如何从 stack.navigation 外部的组件中使用 navigation.navigate【英文标题】:How to use navigation.navigate from a component outside the stack.navigation 【发布时间】:2020-07-24 23:06:19 【问题描述】:

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

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

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

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

【问题讨论】:

【参考方案1】:

我使用 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" );

【讨论】:

【参考方案2】:

screenOptions 中提取navigation 的简单技巧。

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

【讨论】:

【参考方案3】:

试试这个:

创建一个名为: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/

【讨论】:

这不是我前一天回答的字面意思吗? 谢谢你,正是我想要的:D 如果我使用导航的文件不是组件/屏幕,这会起作用吗?如,如果它没有被 NavigationContainer 包裹?我想要实现的是在收到通知时导航到特定屏幕。 (我为此使用react-native-push-notification。)但是推送通知的配置不能添加到任何组件中;它应该在一个单独的文件中。 ref.current 始终为空。我将它记录在 setInterval 中并且它没有被初始化。为什么? 好吧,我输入了 navigationRef=navigationRef 而不是 ref=navigationRef。就这样过去了两个小时。天哪:/【参考方案4】:

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

    使用const myRef = React.createRef() 创建一个引用 将其传递给&lt;NavigationContainer ref=myRef&gt;,然后 使用该引用进行导航,myRef.current?.navigate(name, params)

全部解释here。此处的文档将 ref 的创建分开在一个新文件中,以允许您在没有依赖循环/问题的情况下导入 ref。正如文档所述,您现在可以在任何 js 模块中调用 RootNavigation.navigate('ChatScreen', userName: 'Lucy' );,而不仅仅是在 react 组件中。

不过,在您的情况下,您不需要单独文件中的 ref。

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

&lt;Footer/&gt; 中使用navigationRef.current?.navigate(name, params)

【讨论】:

我发现这比批准的答案更容易理解【参考方案5】:

我最终构建了一个名为 screen 的组件,它只会包装 screen 的内容并根据 props 呈现页眉/页脚:

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>

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

【讨论】:

【参考方案6】:

来自文档。 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)
    />
  );

【讨论】:

显然我已经尝试过文档所说的内容,但这只会显示以下错误:找不到navigation.object,您的组件是否在导航器的屏幕内?

以上是关于如何从 stack.navigation 外部的组件中使用 navigation.navigate的主要内容,如果未能解决你的问题,请参考以下文章

如何从 JSPlumb 中的组中删除项目?

如何在 Zeppelin 中基于 HadoopGroupProvider 中的组配置角色,使用 Knox 提供基于 SAML 的 SSO?

如何使用正则表达式从引号之间提取包含所需字符串的组? [关闭]

如何从MYSQL中的组中查找前N个记录的查询结果

AWK:从线型访问捕获的组

如何将选定的 uitableview 行发送到新创建的组