Motivation

redux-modules was developed to simplify how state transformations are defined and how they're exposed to the view.

Defining state transformations

A state transformation is made up of an action constant, an action creator, and a reducer function. The Redux community has come up with two strategies for organizing these pieces.

The first strategy is to divide these pieces into separate files:

actions/
  todos.js
reducers/
  todos.js
constants/
  todos.js
containers/
  TodoList.jsx
App.jsx

At least 4 files must be created/modified to support a new state transformation

The second strategy is to combine these pieces into a single file:

// constants
export const CREATE_TODO = 'todos/CREATE';
export const DELETE_TODO = 'todos/DELETE';

// action creators
export function createTodo(payload, meta) {
  return {
    type: CREATE_TODO,
    payload,
    meta,
  };
}

export function deleteTodo(payload, meta) {
  return {
    type: DELETE_TODO,
    payload,
    meta,
  };
}

// reducer
export const reducer = (state = List(), action) => {
  switch (action.type) {
    case CREATE_TODO:
      return state.push(fromJS(action.payload));
    case DELETE_TODO:
      return state.delete(action.payload.index);
    default:
      return state;
  }
}

Readability drops as the number of actions increases

Both of these approaches disconnect the constant, the action creator, and the accompanying reducer. Neither approach scales well as new transformations are created. The first option generates 3 files of the same name for every new reducer while second grows out of control after about 10 actions.

A simpler solution

redux-modules aims to streamline the process of defining state transformations by combining the constant and reducer into a single object. createModules then uses these objects to generate action creators for each state transformations.

{
  create: {
    middleware: [
      middlware.propCheck(shape({ description: PropTypes.string }))
    ],
    reducer: (state, {payload}) =>
      state.push(fromJS(payload)),
  }
}

By colocating these concerns, adding a new state transformation is as easy as adding a new object to an array.

Additionally, by generating action creators we're able to operate on actions before they reach the reducer function. This means we can do things like:

  • Introspect for payload typechecking
  • Run transformations on the payload (e.g. for deserializing API responses)
  • Add meta information
  • Change the action type based on some logic

results matching ""

    No results matching ""