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

时间:2018-04-12 06:27:56

标签: reactjs react-native react-router react-navigation react-native-navigation

我的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'
});

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

3 个答案:

答案 0 :(得分:2)

您可以按this official guide创建导航服务。然后使用FcmHandler中的导航服务代替navigation道具。这样就不需要将FcmHandler作为导航器的子项。

如果您使用的是redux或mobx,最好将导航状态移至商店以便于访问。对于redux,有一个official integration guide。对于mobx,您可以尝试this

答案 1 :(得分:1)

对于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,
      }

解释

config会在navigator's dispatch被初始化时初始化redux-navigation对象,因此您可以dispatch any navigation action wrt < em>服务组件。

使用

NavigationServices.navigate('ScreenName')

<强>更新 React Navigation现在提供HOC wrapper withNavigation,将导航道具传递给包装组件。

  

当你无法直接将导航道具传递给组件,或者在深层嵌套的孩子的情况下不想传递它时,它很有用。

docs中提到了用法。

答案 2 :(得分:0)

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

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

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