Sometimes you need to trigger a navigation action from places where you do not have access to the
navigation prop, such as a Redux middleware. For such cases, you can dispatch navigation actions from the navigation container.
If you're looking for a way to navigate from inside a component without needing to pass the
navigation prop down, see
useNavigation. Do not use this method when you have access to a
navigation prop or
useNavigation since it will behave differently, and many helper methods specific to screens won't be available.
You can get access to the root navigation object through a
ref and pass it to the
RootNavigation which we will later use to navigate.
In the next step, we define
RootNavigation, which is a simple module with functions that dispatch user-defined navigation actions.
RootNavigation and call functions which you exported from it. You may use this approach outside of your React components and, in fact, it works just as well when used from within them.
navigate, you can add other navigation actions:
Note that a stack navigators needs to be rendered to handle this action. You may want to check the docs for nesting for more details.
When writing tests, you may mock the navigation functions, and make assertions on whether the correct functions are called with the correct parameters.
When using this pattern, you need to keep few things in mind to avoid crashes in your app.
- The ref is set only after the navigation container renders, this can be async when handling deep links
- A navigator needs to be rendered to be able to handle actions
If you try to navigate without rendering a navigator or before the navigator finishes mounting, it will throw and crash your app if not handled. So you'll need to add an additional check to decide what to do until your app mounts.
For an example, consider the following scenario, you have a screen somewhere in the app, and that screen dispatches a redux action on
componentDidMount. You are listening for this action in your middleware and try to perform navigation when you get it. This will throw an error, because by this time, the parent navigator hasn't finished mounting and isn't ready. Parent's
componentDidMount is always called after child's
To avoid this, you can set a ref to tell you that your app has finished mounting, and check that ref before performing any navigation. To do this, we can use the
onReady callback in our
Also export this ref from our
Note that this only handles the case when you're dispatching actions before the container finishes mounting. You'll still have an error if you are not rendering any navigators. A navigator must be rendered to be able to dispatch actions.
If you're unsure if a navigator is rendered, you can call
navigationRef.current.getRootState(), and it'll return a valid state object if any navigators are rendered, otherwise it will return