Ducks Modular Redux

A proposal for bundling reducers, action types and actions when using Redux
Alternatives To Ducks Modular Redux
Project NameStarsDownloadsRepos Using ThisPackages Using ThisMost Recent CommitTotal ReleasesLatest ReleaseOpen IssuesLicenseLanguage
Immer25,25387,9802,76823 days ago155June 13, 202227mitJavaScript
Create the next immutable state by mutating the current one
Redux Persist12,6135,4877622 days ago186September 02, 2019576mitTypeScript
persist and rehydrate a redux store
Redux Toolkit9,535251,12716 hours ago56August 28, 2022266mitTypeScript
The official, opinionated, batteries-included toolset for efficient Redux development
Ducks Modular Redux9,156
2 years ago36JavaScript
A proposal for bundling reducers, action types and actions when using Redux
Rematch8,1752101099 months ago76November 09, 202119mitTypeScript
The Redux Framework
Reswift7,386
155a month ago9January 15, 201849mitSwift
Unidirectional Data Flow in Swift - Inspired by Redux
Redux Ecosystem Links5,143
10 months ago30
A categorized list of Redux-related addons, libraries, and utilities
Connected React Router4,7312,0666203 months ago51July 11, 2022175mitJavaScript
A Redux binding for React Router v4
Store3,98226 years ago8June 07, 201710mitTypeScript
RxJS powered state management for Angular applications, inspired by Redux
Redux Orm2,96682325 months ago70August 11, 2021115mitJavaScript
NOT MAINTAINED – A small, simple and immutable ORM to manage relational data in your Redux store.
Alternatives To Ducks Modular Redux
Select To Compare


Alternative Project Comparisons
Readme

Ducks: Redux Reducer Bundles

I find as I am building my redux app, one piece of functionality at a time, I keep needing to add {actionTypes, actions, reducer} tuples for each use case. I have been keeping these in separate files and even separate folders, however 95% of the time, it's only one reducer/actions pair that ever needs their associated actions.

To me, it makes more sense for these pieces to be bundled together in an isolated module that is self contained, and can even be packaged easily into a library.

The Proposal

Example

See also: Common JS Example.

// widgets.js

// Actions
const LOAD   = 'my-app/widgets/LOAD';
const CREATE = 'my-app/widgets/CREATE';
const UPDATE = 'my-app/widgets/UPDATE';
const REMOVE = 'my-app/widgets/REMOVE';

// Reducer
export default function reducer(state = {}, action = {}) {
  switch (action.type) {
    // do reducer stuff
    default: return state;
  }
}

// Action Creators
export function loadWidgets() {
  return { type: LOAD };
}

export function createWidget(widget) {
  return { type: CREATE, widget };
}

export function updateWidget(widget) {
  return { type: UPDATE, widget };
}

export function removeWidget(widget) {
  return { type: REMOVE, widget };
}

// side effects, only as applicable
// e.g. thunks, epics, etc
export function getWidget () {
  return dispatch => get('/widget').then(widget => dispatch(updateWidget(widget)))
}

Rules

A module...

  1. MUST export default a function called reducer()
  2. MUST export its action creators as functions
  3. MUST have action types in the form npm-module-or-app/reducer/ACTION_TYPE
  4. MAY export its action types as UPPER_SNAKE_CASE, if an external reducer needs to listen for them, or if it is a published reusable library

These same guidelines are recommended for {actionType, action, reducer} bundles that are shared as reusable Redux libraries.

Name

Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles "ducks", as in the last syllable of "redux".

Usage

You can still do:

import { combineReducers } from 'redux';
import * as reducers from './ducks/index';

const rootReducer = combineReducers(reducers);
export default rootReducer;

You can still do:

import * as widgetActions from './ducks/widgets';

...and it will only import the action creators, ready to be passed to bindActionCreators().

Actually, it'll also import default, which will be the reducer function. It'll add an action creator named default that won't work. If that's a problem for you, you should enumerate each action creator when importing.

There will be some times when you want to export something other than an action creator. That's okay, too. The rules don't say that you can only export action creators. When that happens, you'll just have to enumerate the action creators that you want. Not a big deal.

import {loadWidgets, createWidget, updateWidget, removeWidget} from './ducks/widgets';
// ...
bindActionCreators({loadWidgets, createWidget, updateWidget, removeWidget}, dispatch);

Example

React Redux Universal Hot Example uses ducks. See /src/redux/modules.

Todomvc using ducks.

BattleCry generators

There are configurable BattleCry generators ready to be downloaded and help scaffolding ducks:

npm install -g battlecry
cry download generator erikras/ducks-modular-redux
cry init duck

Run cry --help to check more info about the generators available;

Implementation

The migration to this code structure was painless, and I foresee it reducing much future development misery.

Although it's completely feasable to implement it without any extra library, there are some tools that might help you:

  • extensible-duck - Implementation of the Ducks proposal. With this library you can create reusable and extensible ducks.
  • saga-duck - Implementation of the Ducks proposal in Typescript with sagas in mind. Results in reusable and extensible ducks.
  • redux-duck - Helper function to create Redux modules using the ducks-modular-redux proposal
  • modular-redux-thunk - A ducks-inspired package to help organize actions, reducers, and selectors together - with built-in redux-thunk support for async actions.
  • molecular-js - Set of utilities to ease the development of modular state management patterns with Redux (also known as ducks).
  • ducks-reducer - Function to combine ducks object reducers into one reducer (equivalent to combineReducers), and function ducks-middleware to combine ducks object middleware into one single middleware compatible with applyMiddleware.
  • simple-duck - Class based implementation of modules system, inspired by ducks-modular-redux. All OOP benefits like inheritance and composition. Support combining of duck-module classes and regular reducer functions using combineModules function.

Please submit any feedback via an issue or a tweet to @erikras. It will be much appreciated.

Happy coding!

-- Erik Rasmussen

Translation

한국어 中文 Türkçe


C'mon! Let's migrate all our reducers!

Photo credit to Airwolfhound.


Beerpay Beerpay

Popular Redux Projects
Popular Reducer Projects
Popular User Interface Categories

Get A Weekly Email With Trending Projects For These Categories
No Spam. Unsubscribe easily at any time.
Javascript
Redux
Reducer
Proposal