【问题标题】:Get navigation props in an independent component React Native在独立组件 React Native 中获取导航道具
【发布时间】:2018-09-22 04:30:28
【问题描述】:

我的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 组件被调用,但我无法访问位于 &lt;Root/&gt; 组件内的导航道具。

&lt;Root/&gt; 组件包含以下内容

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


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


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

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

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

【问题讨论】:

  • 你在使用redux-navigation吗?我可能有一个解决方案。
  • 我不是,但如果你能告诉我解决方案,它可能会帮助我实现我的目标,或者可能帮助任何偶然发现这个问题的人。

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


【解决方案1】:

经过一番研究,我发现最简单的方法是关注他们的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 并在返回函数中创建了对它的引用:

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

【讨论】:

    【解决方案2】:

    对于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,它将导航道具传递到一个包装的组件中。

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

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

    【讨论】:

    • 在使用此解决方案时,假设我将一些参数传递给 ScreenName 路由。我如何访问它们?
    【解决方案3】:

    您可以关注this official guide 来创建您的导航服务。然后使用FcmHandler 中的导航服务而不是navigation 属性。这样就不需要将FcmHandler 作为导航器的子级。

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

    【讨论】:

      猜你喜欢
      • 2020-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多