title: react-navigation: Invariant Violation on navigating in push notification using Expo.addListener
body: <p>When my application receives a push notification, it should navigate to the appropriate screen using a routeName param in the notification data. </p>
  
  <p>This was working until I abstracted our navigation following the NavigationService pattern described in <a href="https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html" rel="nofollow noreferrer">react-navigation docs</a>, and fleshed out more in a react-navigation issue <a href="https://github.com/react-navigation/react-navigation/issues/1439#issuecomment-303661539" rel="nofollow noreferrer">here</a>.</p>
  
  <p>The problem I'm running into is <a href="https://github.com/react-navigation/react-navigation/blob/d746a587b09676c9ac85d64298340fd5cd0df7e4/src/createNavigationContainer.js#L314" rel="nofollow noreferrer">from react-navigation</a>: <strong>Invariant Violation: should be set in constructor if stateful</strong></p>
  
  <p>To resolve this, I've tried moving around the <code>addListener</code> call. I've tried the App <code>componentDidMount</code>, the AppWithNavigation ref callback (this seems like a bad idea), and the <code>setContent</code> method of NavigationService.</p>
  
  <p>I've tried variations of the listener that use NavigationService, and that use <code>NavigationActions.navigate</code> directly with <code>store.dispatch</code> in App.</p>
  
  <p>My theory is that the navigation container is changing, but navigation works fine except for when the app is closed and a notification comes in. I've even had it working with the app open and in that case it did move to the right screen.</p>
  
  <p>What am I missing here?</p>
  
  <p><strong>Listener looks like this:</strong></p>
  
  <pre><code>Notifications.addListener(({data}: {data: NotificationType}) =&gt; {
    const {routeName, params} = data;
    NavigationService.navigate({
      routeName,
      params,
    });
  });
  </code></pre>
  
  <p><strong>NavigationService.js:</strong></p>
  
  <pre><code>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,
  };
  </code></pre>
  
  <p><strong>Part of Navigators.js</strong></p>
  
  <pre><code>class AppWithNavigationState extends Component {
    render() {
      return (
        &lt;React.Fragment&gt;
          {/* Fix for white icons on white status bar bug on iOS */}
          {!isAndroid &amp;&amp; &lt;StatusBar barStyle="dark-content" /&gt;}
          &lt;RootStack
            persistenceKey="NavigationState-2"
            ref={navigatorRef =&gt; NavigatorService.setContainer(navigatorRef)}
          /&gt;
        &lt;/React.Fragment&gt;
      );
    }
  }
  
  export default AppWithNavigationState;
  </code></pre>