реагировать на навигацию: нарушение инварианта при навигации в push-уведомлениях с использованием Expo.addListener - PullRequest
0 голосов
/ 06 сентября 2018

Когда мое приложение получает push-уведомление, оно должно перейти к соответствующему экрану, используя параметр routeName в данных уведомления.

Это работало до тех пор, пока я не абстрагировал нашу навигацию по шаблону NavigationService, описанному в документах по реактивной навигации , и не уточнил подробнее в проблеме реагирования-навигации здесь .

Проблема, с которой я сталкиваюсь: от реагирования-навигации : Инвариантное нарушение: должно быть установлено в конструкторе, если с состоянием

Чтобы решить эту проблему, я попытался передвинуть вызов addListener. Я попробовал App componentDidMount, обратный вызов ref из AppWithNavigation (это кажется плохой идеей) и setContent метод NavigationService.

Я пробовал варианты слушателя, которые используют NavigationService и используют NavigationActions.navigate напрямую с store.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;

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Это решение, которое я выбрал. Не идеален и будет стремиться обновиться до реакции-навигации 3 как можно скорее. Я использую renderLoadingExperimental для рендеринга SplashScreen во время загрузки. Я не могу получить уведомление после завершения загрузки, поэтому я добавил onUnmount к своему SplashScreen и обработал там регистрацию.

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;
0 голосов
/ 06 февраля 2019

Я столкнулся с той же проблемой. Моя установка очень похожа на вашу, проблема была в том, что я делал навигацию в саге в качестве побочного эффекта до того, как навигатор приложения завершил загрузку. Проверьте, используете ли вы persistenceKey, если это так, предыдущее состояние гидратируется асинхронно, что и стало причиной моей проблемы. У меня был обратный вызов navigationReady в моем главном навигаторе, который был на componentDidMount, но я думаю, что мне придется переместить его вниз к реальному экрану, чтобы избежать проблемы. В настоящее время я не могу найти правильный способ подписаться на действие Navigation / INIT, отправляемое контейнером после того, как все восстановлено.

...