反应导航:使用 Expo.addListener 在推送通知中导航时的不变违规

react-navigation: Invariant Violation on navigating in push notification using Expo.addListener

当我的应用程序收到推送通知时,它应该使用通知数据中的 routeName 参数导航到适当的屏幕。

这一直有效,直到我按照 react-navigation docs, and fleshed out more in a react-navigation issue here 中描述的 NavigationService 模式抽象了我们的导航。

我 运行 遇到的问题是 from react-navigationInvariant Violation: should be set in constructor if stateful

为了解决这个问题,我尝试绕过 addListener 调用。我已经尝试了 App componentDidMount、AppWithNavigation ref 回调(这似乎是个坏主意)和 NavigationService 的 setContent 方法。

我试过使用 NavigationService 的侦听器变体,并在应用程序中直接使用 NavigationActions.navigatestore.dispatch

我的理论是导航容器正在改变,但导航工作正常,除了应用程序关闭和通知进来时。我什至在应用程序打开时让它工作,在那种情况下它确实移动了到右边的屏幕。

我在这里错过了什么?

听众看起来像这样:

Notifications.addListener(({data}: {data: NotificationType}) => {
  const {routeName, params} = data;
  NavigationService.navigate({
    routeName,
    params,
  });
});

NavigationService.js:

import {StackActions, NavigationActions} from 'react-navigation';
import type {NavigationParams, NavigationRoute} from 'react-navigation';

import {LOGOUT} from '../redux/auth';

let _container; // eslint-disable-line

function setContainer(container: Object) {
  _container = container;
}

function reset(routeName: NavigationRoute, params?: NavigationParams) {
  _container.dispatch(
    StackActions.reset({
      index: 0,
      actions: [
        NavigationActions.navigate({
          routeName,
          params,
        }),
      ],
    }),
  );
}

function navigate(routeName: string, params?: NavigationParams) {
  _container.dispatch(
    NavigationActions.navigate({
      routeName,
      params,
    }),
  );
}

function goBack(options) {
  _container.dispatch(NavigationActions.back(options));
}

function getCurrentRoute(): NavigationRoute | null {
  if (!_container || !_container.state.nav) {
    return null;
  }

  return _container.state.nav.routes[_container.state.nav.index] || null;
}

export function logOut() {
  _container.dispatch({type: LOGOUT});
  reset('Welcome');
}

export default {
  setContainer,
  navigate,
  reset,
  goBack,
  logOut,
};

部分Navigators.js

class AppWithNavigationState extends Component {
  render() {
    return (
      <React.Fragment>
        {/* Fix for white icons on white status bar bug on iOS */}
        {!isAndroid && <StatusBar barStyle="dark-content" />}
        <RootStack
          persistenceKey="NavigationState-2"
          ref={navigatorRef => NavigatorService.setContainer(navigatorRef)}
        />
      </React.Fragment>
    );
  }
}

export default AppWithNavigationState;

我遇到了同样的问题。我的设置与您的设置非常相似,问题是在应用程序导航器完成启动之前,我在 saga 中进行导航作为副作用。检查您是否正在使用 persistenceKey,如果是,则之前的状态会异步水化,这就是我的问题的原因。 我在 componentDidMount 的主导航器中有一个回调 navigationReady,但我认为我必须将其向下移动到实际屏幕以避免出现问题。目前我找不到合适的方法来订阅容器在完成恢复后调度的动作 Navigation / INIT

这是我最终得到的解决方案。不理想,希望尽快升级到 react-navigation 3。我正在使用 renderLoadingExperimental 在加载时呈现 SplashScreen。加载完成后我无法收到通知,因此我在我的 SplashScreen 中添加了一个 onUnmount 并在那里处理注册。

class AppWithNavigationState extends Component {
  render() {
    return (
      <React.Fragment>
        <RootStack
          persistenceKey="NavigationState-2"
          ref={navigatorRef => NavigationService.setContainer(navigatorRef)}
          renderLoadingExperimental={() => (
            <SplashScreen
              source="RootStack"
              onUnmount={() => {
                Notifications.addListener(({data}) => {
                  NavigationService.navigate(data.routeName, data.params);
                  if (Platform.OS === 'android')
                    Notifications.dismissAllNotificationsAsync();
                });
              }}
            />
          )}
        />
      </React.Fragment>
    );
  }
}

export default AppWithNavigationState;