如何 link 'from outside' 进入导航器(例如从全局页脚)

How to link 'from outside' into Navigator (for example from a global footer)

使用 React Navigation,有没有办法 link 从外部 到导航器内部的特定 path/screen?

例如实现全局页脚,如下所示:

<Provider store={store}>
  <View>
     <AppNavigator />
     <MyFooter /> // Link from here to a path/screen inside AppNavigator
  </View>
</Provider>

我认为 refs 在这里可能行得通。如果你想从声明它的同一级别使用 Navigator,你可以使用 react 的 refs 并将 props 传递给 MyFooter。查看官方文档中的example

const AppNavigator = StackNavigator(SomeAppRouteConfigs);

class App extends React.Component {
  someFunction = () => {
    // call navigate for AppNavigator here:
    this.navigator && this.navigator.dispatch({ type: 'Navigate', routeName, params });
  }
  render() {
    return (
      <View>
        <AppNavigator ref={nav => { this.navigator = nav; }} />
        <MyFooter someFunction={this.someFunction} />
      </View>
    );
  }
}

转到此 link: https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html

React 导航版本:5.x

有时您需要从无法访问 navigation 道具的地方触发导航操作,例如 Redux 中间件。对于这种情况,您可以从导航容器中调度导航操作。

如果您正在寻找一种无需向下传递 navigation 属性即可从组件内部导航的方法,请参阅 useNavigation

您可以通过 ref 访问根导航 object 并将其传递给我们稍后将用于导航的 RootNavigation

// App.js

import { NavigationContainer } from '@react-navigation/native';
import { navigationRef } from './RootNavigation';

export default function App() {
  return (
    <NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
  );
}

下一步,我们定义 RootNavigation,这是一个简单的模块,具有调度 user-defined 导航操作的功能。

// RootNavigation.js

import * as React from 'react';

export const navigationRef = React.createRef();

export function navigate(name, params) {
  navigationRef.current?.navigate(name, params);
}

// add other navigation functions that you need and export them

然后,在您的任何 javascript 模块中,只需导入 RootNavigation 并调用您从中导出的函数。您可以在 React 组件之外使用这种方法,事实上,在组件内部使用它同样有效。

// any js module
import * as RootNavigation from './path/to/RootNavigation.js';

// ...

RootNavigation.navigate('ChatScreen', { userName: 'Lucy' });

除了navigate,您还可以添加其他导航操作:

import { StackActions } from '@react-navigation/native';

export function push(...args) {
  navigationRef.current?.dispatch(StackActions.push(...args));
}

请注意,需要呈现堆栈导航器来处理此操作。您可能需要查看 docs for nesting 了解更多详情。

编写测试时,您可以模拟导航函数,并断言是否使用正确的参数调用了正确的函数。

处理初始化

使用此模式时,您需要牢记一些注意事项以避免应用程序崩溃。

  • 仅在导航容器呈现后设置 ref
  • 需要呈现导航器才能处理操作

如果您尝试在不呈现导航器的情况下或在导航器完成安装之前进行导航,如果不加以处理,它将抛出并使您的应用程序崩溃。因此,您需要添加额外的检查来决定在您的应用安装之前要做什么。

例如,请考虑以下场景,您在应用程序的某处有一个屏幕,并且该屏幕在 useEffect/componentDidMount 上调度了一个 redux 操作。您正在中间件中监听此操作,并在获取时尝试执行导航。这将引发错误,因为此时 parent 导航器尚未完成安装。 Parent 的 useEffect/componentDidMount 总是在 之后被调用 child 的 useEffect/componentDidMount .

为避免这种情况,您可以设置一个 ref 来告诉您您的应用已完成安装,并在执行任何导航之前检查该 ref。为此,我们可以在我们的根组件中使用 useEffect

// App.js

import { NavigationContainer } from '@react-navigation/native';
import { navigationRef, isMountedRef } from './RootNavigation';

export default function App() {
  React.useEffect(() => {
    isMountedRef.current = true;

    return () => (isMountedRef.current = false);
  }, []);

  return (
    <NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
  );
}

也从我们的 RootNavigation:

中导出这个 ref
// RootNavigation.js

import * as React from 'react';

export const isMountedRef = React.createRef();

export const navigationRef = React.createRef();

export function navigate(name, params) {
  if (isMountedRef.current && navigationRef.current) {
    // Perform navigation if the app has mounted
    navigationRef.current.navigate(name, params);
  } else {
    // You can decide what to do if the app hasn't mounted
    // You can ignore this, or add these actions to a queue you can call later
  }
}