5
votes

I'm having trouble understanding how best to use Redux-Saga with React-Navigation.

From Redux-Saga docs:

redux-saga is a library that aims to make side effects (i.e. asynchronous things like data fetching and impure things like accessing the browser cache) in React/Redux applications easier and better.

The mental model is that a saga is like a separate thread in your application that's solely responsible for side effects.

In React-Navigation's redux integration section it links to this example which shows Redux being used without redux-saga. In this example the components dispatch actions directly to the reducers with no middleware.

I.e.

src/components/LoginScreen.js

const LoginScreen = ({ navigation }) => (
  <View style={styles.container}>
    <Text style={styles.welcome}>
      Screen A
    </Text>
    <Text style={styles.instructions}>
      This is great
    </Text>
    <Button
      onPress={() => navigation.dispatch({ type: 'Login' })}
      title="Log in"
    />
  </View>
);

src/reducers/nav.js

function nav(state = initialNavState, action) {
  let nextState;
  switch (action.type) {
    case 'Login':
      nextState = AppNavigator.router.getStateForAction(
        NavigationActions.back(),
        state
      );
      break;
    case 'Logout':
      nextState = AppNavigator.router.getStateForAction(
        NavigationActions.navigate({ routeName: 'Login' }),
        state
      );
      break;
    default:
      nextState = AppNavigator.router.getStateForAction(action, state);
      break;
  }

  // Simply return the original `state` if `nextState` is null or undefined.
  return nextState || state;
}

With this in mind, I see two options:

1) Separate regular actions (navigation, etc.) from side-effect inducing actions (asynchronous api requests) and only use the latter with redux-sagas. I assume this would require the need for the mapDispatchToProps option in the connect() wrapper.

2) Go all or nothing and make sure everything is dispatched through redux-sagas so actions and reducers can remain as pure as possible. This feels needlessly complicated for just navigation though.

Which would you say is better practice?

1

1 Answers

2
votes

Not sure you've quite grasped the concept of sagas. With sagas you can declare side effects for some actions and those side effects might dispatch other actions. But you don't change the way you dispatch your actions. Also this has nothing to do with navigation. Navigation doesn't have any side effects, it's pure state manipulation with reducers. Of course some navigation actions could trigger side effects for loading data. Then you'd use sagas on those specific actions that have side effects. But that is just like any other side effect. So your decision about using redux saga should have nothing to do with your navigation solution.

In General a saga will react to actions with triggering side effects and potentially dispatching other actions. And a reducer will react to actions by changing the state without side effects.

Your alternatives are to handle side effects before you dispatch the action in the action creators (like redux-thunk does). And there's also redux-observable which has a similar pattern to redux saga but is based on RxJS and doesn't use the elm patterns that redux saga has.