Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing navigator in Actions with React-Native and Redux

Using React-Native (0.19) and Redux, I'm able to navigate from scene to scene in React Components like so:

this.props.navigator.push({
 title: "Registrations",
 component: RegistrationContainer
});

Additionally I'd like to be able push components to the navigator from anywhere in the app (reducers and/or actions).

Example Flow:

  1. User fills out form and presses Submit
  2. We dispatch the form data to an action
  3. The action sets state that it has started to send data across the wire
  4. The action fetches the data
  5. When complete, action dispatches that the submission has ended
  6. Action navigates to the new data recently created

Problems I'm seeing with my approach:

  • The navigator is in the props, not the state. In the reducer, I do not have access to the props
  • I need to pass navigator into any action that needs it.

I feel like I'm missing something slightly simple on how to access Navigator from actions without sending in as a parameter.

like image 613
Jesse Wolgamott Avatar asked Feb 01 '16 20:02

Jesse Wolgamott


People also ask

How do you navigate in a Redux action?

To handle your app's navigation state in Redux, you can pass your own navigation prop to a navigator. Once you pass your own navigation prop to the navigator, the default navigation prop gets destroyed. You must construct your own navigation prop with state , dispatch , and addListener properties.


2 Answers

In my opinion the best way to handle the navigation with Redux is with react-native-router-flux, because it can delegate all the navigation logic to Redux:

  • You can change the route from the reducer;

  • You can connect the router to the store and dispatch its own actions that will inform the store about route changes (BEFORE_ROUTE, AFTER_ROUTE, AFTER_POP, BEFORE_POP, AFTER_DISMISS, BEFORE_DISMISS);


An example

Here is an example on how easily you can save the currently focused route in the store and handle it in a component (that will be aware of being focused):

1. Connect a <Route> to Redux
Connecting a <Route> to Redux is easy, instead of:

<Route name="register" component={RegisterScreen} title="Register" />

you might write:

<Route name="register" component={connect(selectFnForRegister)(RegisterScreen)} title="Register" />

You can also simply connect the component itself in its own file like you usually do.


2. Connect a <Router> to Redux
If you need to inform Redux of the navigation status (i.e. when you pop a route) just override the <Router> component included in react-native-router-flux with a connected one:

import ReactNativeRouter, { Actions, Router } from 'react-native-router-flux'
const Router = connect()(ReactNativeRouter.Router) 

Now when you use a <Router> it will be connected to the store and will trigger the following actions:

  • Actions.BEFORE_ROUTE
  • Actions.AFTER_ROUTE
  • Actions.AFTER_POP
  • Actions.BEFORE_POP
  • Actions.AFTER_DISMISS
  • Actions.BEFORE_DISMISS

Take a look at this for an example.


3. Catch the interested actions in your reducer
For this example I have a global reducer (where I keep the information needed by all my app) where I set the currentRoute:

case Actions.AFTER_ROUTE:
case Actions.AFTER_POP:
  return state.set('currentRoute', action.name)

Now the reducer will catch every route change and update global.currentRoute with the currently focused route.
You also can do many other interesting things from here, like saving an history of the navigation itself in an array!


4. Update your component on focus
I'm doing it on componentDidUpdate of my component of the route named payment. If global.currentRoute is payment and the previous global.currentRoute was different, than the component has just been focused.

  componentDidUpdate(prevProps) {
    const prevRoute = prevProps.global.currentRoute
    const currentRoute = this.props.global.currentRoute
    if (currentRoute === 'payment' && prevRoute !== currentRoute) {
      this.props.actions.doSomething()
    }
  }

P.S.: Remember to check currentRoute === 'payment', otherwise you'll start doSomething() on every route change!


Also, take a look a the README.md for learning other stuff about the integration with Redux.
Hope it helps, long live Redux!

like image 158
Matteo Mazzarolo Avatar answered Oct 21 '22 07:10

Matteo Mazzarolo


Maybe you could pass the information about title and component in an action and the component with the navigator can then push the right scene with the information of the state.

like image 27
Julius Breckel Avatar answered Oct 21 '22 07:10

Julius Breckel