在独立组件 React Native 中获取导航道具

Get navigation props in an independent component React Native

我的 app.js 文件看起来像这样

export default class App extends React.Component {

render() {
    return (
        <Root style={{
            flex: 1
        }}>
            <FcmHandler/>
        </Root>
    )
 }

}

Root 组件是整个应用程序以及所有功能所在的地方,FcmHandler 是我处理与通知等相关的功能的地方。在 FcmHandler 我有一个单击通知时获取回调的方法,在此回调中,我需要根据通知点击导航到应用程序中的特定屏幕。

问题是使用 FcmHandler 组件上方的当前代码甚至从未初始化。

如果我尝试这样的事情

 export default class App extends React.Component {

render() {
    return (
        <View style={{
            flex: 1
        }}>
            <Root/>
            <FcmHandler/>
        </View>
    )
 }
}

FcmHandler 组件被调用,但我无法访问位于 <Root/> 组件内的导航道具。

<Root/> 组件包含以下

const ArticleStack = StackNavigator(
    {
        ...
    }
);


const SettingsStack = StackNavigator({
    ...
});


export const Root = StackNavigator({
    Articles: {
        screen: ArticleStack
    },
    Settings: {
        screen: SettingsStack

    },
}, {
    mode: 'modal',
    headerMode: 'none'
});

我试图实现的基本目标是,当单击通知时,无论应用当前在哪个屏幕上,我都应该能够导航到特定屏幕。我不想在我拥有的每个屏幕组件中都编写导航代码,这似乎是多余的。

对于 react-navigation 用户,一个非常酷的方法是创建自己的 导航服务

您可以初始化您的 导航服务 模块,在初始化您的导航存储期间,如他们的 docs

中所述
 <AppNavigator navigation={addNavigationHelpers({
    dispatch: this.props.dispatch,
    state: this.props.nav,
    addListener,
  })} />
 // Just add another line to config the navigator object
  NavigationService.configNavigator(dispatch) <== This is the important part

NavigationService.js

import { NavigationActions } from 'react-navigation'

      let config = {}

      const configNavigator = nav => {
        config.navigator = nav
      }

      const reset = (routeName, params) => {
        let action = NavigationActions.reset({
          index: 0,
          key: null,
          actions: [
            NavigationActions.navigate({
              type: 'Navigation/NAVIGATE',
              routeName,
              params,
            }),
          ],
        })
        config.navigator(action)
      }

      const navigate = (routeName, params) => {
        let action = NavigationActions.navigate({
          type: 'Navigation/NAVIGATE',
          routeName,
          params,
        })
        config.navigator(action)
      }

      const navigateDeep = actions => {
        let action = actions.reduceRight(
          (prevAction, action) =>
            NavigationActions.navigate({
              type: 'Navigation/NAVIGATE',
              routeName: action.routeName,
              params: action.params,
              action: prevAction,
            }),
          undefined
        )
        config.navigator(action)
      }

      const goBack = () => {
        if (config.navigator) {
          let action = NavigationActions.back({})
          config.navigator(action)
        }
      }

      export default {
        configNavigator,
        navigateDeep,
        navigate,
        reset,
        goBack,
      }

解释

每当您的 redux-navigation 初始化时,config 都会初始化 navigator's dispatch 对象,因此您可以 dispatch any navigation actionwrt 服务组件.

中存在方法

使用

NavigationServices.navigate('ScreenName')

更新: React Navigation 现在提供 HOC wrapper withNavigation,将导航道具传递到包装组件中。

It's useful when you cannot pass the navigation prop into the component directly, or don't want to pass it in case of a deeply nested child.

他们的 docs 中很好地提到了用法。

您可以按照this official guide创建您的导航服务。然后使用 FcmHandler 中的导航服务而不是 navigation 属性。这样就不需要把 FcmHandler 作为导航器的子项了。

如果您使用的是 redux 或 mobx,最好将您的导航状态移动到商店以便于访问。对于 redux,有一个 official integration guide. For mobx, you can try this.

经过一些研究,我发现最简单的方法是遵循他们的 official documentation

  1. 我在 ./misc 文件夹中创建了一个 RootNavigation.js 文件;

import * as React from 'react';

export const navigationRef = React.createRef();
export function navigate(name, params) {
  navigationRef.current?.navigate(name, params);
}

  1. 我将其导入 App.js 并在 return 函数中创建了对它的引用:

import React from 'react'
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { navigationRef } from './misc/rootNavigation'; <- navigationRef is imported

…

const Stack = createStackNavigator();

function App() {
  return (
    <Provider store={store}>
      <NavigationContainer ref={navigationRef}> <— reference to navigationRef
        <Stack.Navigator>
…
          <Stack.Screen
            name="Screen"
            component={Screen}
            options={{
              title: “Hello”,
              headerLeft: () => <ScreenButton/>
          }} />

        </Stack.Navigator>
      </NavigationContainer>
    </Provider>
  );
}

export default App

  1. 我在 ScreenButton 组件中调用了它

import React, { Component } from 'react'
…
import * as RootNavigation from '../misc/rootNavigation'; <—- imported

class RoomButton extends Component {

    constructor(props) {
        super(props)
    }

    render() {
        return (
            <TouchableOpacity onPress={
                () => {RootNavigation.navigate( 'RoomSelectorScreen' ) <—- called here
            …
            </TouchableOpacity>
        )
    }
}