Search code examples
reactjsreduxredux-sagaredux-thunkredux-persist

How to chain redux actions using returned result of the previous action?


I'm building an app in React Native, and using Redux with redux-persist to act as on device database.

The crux of the issue is, how do I return the result of a redux action, to then dispatch another action with this data? Read on for more specifics.

The user can create custom habit types. When doing so, I dispatch an action to create a habit type in the store (e.g. "running"). This action generates a new unique UUID for the habit type. I then want to add this newly created habit type to a routine (e.g. "morning routine"), and so I need to receive back the UUID of the habit type and call another dispatch to add it to the routine.

I'm using immer to make manipulating the state in my reducers simpler, and have this code (simplified example):

import produce from "immer";

const userReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_CUSTOM_HABIT_TYPE: {
      return produce(state, draftState => {
        const newHabitType = {
          id: generateUuid(),
          name,
        };

        draftState.customHabitTypes.push(newHabitType);

        return draftState;
      });
    }
  }
};

I'm then dispatching it in my component, like so (simplified):

dispatch({
  type: ADD_CUSTOM_HABIT_TYPE,
  name: "running",
});

How can I then say, after creating this new habit type, to dispatch another action and add it to my routine?

I've looked at redux-thunk and redux-saga, and spent hours reading about these and trying to get redux-thunk to work, but to no avail. I'm sure this must be simple, but I'm coming up blank, and so maybe others are too, hence this post.


Solution

  • A very simple solution would be to generate the unique id before dispatching the action.

    Example

    const newHabitType = {
      id: generateUuid(),
      name,
    };
    
    dispatch({
      type: ADD_CUSTOM_HABIT_TYPE,
      habit: newHabitType,
    });
    
    dispatch({
      type: ADD_CUSTOM_HABIT_TO_ROUTINE,
      habit: newHabitType.id,
    });
    

    Pros

    1. You no longer need to chain actions per se, you just need to dispatch them in order.
    2. This preserves one of the most important Redux guidelines: your reducer should not have any side effects (in your case, generating a random id). reference

    Cons

    1. If you create the new habits in multiple places, you will have to generate the unique ids in every place where you dispatch the action. This might lead to repeated code. The solution to this would be to encapsulate the whole logic for creating the habits to a single component and then reuse this component everywhere.