• Stars
    star
    9,586
  • Rank 3,710 (Top 0.08 %)
  • Language
    JavaScript
  • Created over 9 years ago
  • Updated almost 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A proposal for bundling reducers, action types and actions when using Redux

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

More Repositories

1

react-redux-universal-hot-example

A starter boilerplate for a universal webapp using express, react, redux, webpack, and react-transform
JavaScript
12,008
star
2

redux-form-material-ui

A set of wrapper components to facilitate using Material UI with Redux Form
JavaScript
831
star
3

multireducer

A utility to wrap many copies of a single Redux reducer into a single key-based reducer.
JavaScript
423
star
4

lru-memoize

A utility to provide LRU memoization for any js function
JavaScript
317
star
5

styled-components-theme

Defines themes via flexible color selectors for use with styled-components
JavaScript
306
star
6

react-native-listener

A utility component to allow easy access to browser native events
JavaScript
136
star
7

remix-conf-2022

XState on the backend!
CSS
107
star
8

react-pdfjs

A React component to wrap PDF.js
JavaScript
81
star
9

react-redux-promise-listener

A React component and Redux middleware that allows actions to be converted into Promises
JavaScript
71
star
10

audiocard

⏯️ AudioCard - Opinionated, responsive, audio player compatible with Twitter Cards
TypeScript
66
star
11

map-props

A higher order React component and allows mapping prop values passed in to other prop values expected by the wrapped component
JavaScript
45
star
12

react-lazy-cache

A utility to lazily calculate and cache values in a react component based on props
JavaScript
45
star
13

redux-promise-listener

A Redux middleware that allows actions to be converted into Promises
JavaScript
44
star
14

reactalicante2018

Code from my talk at React Alicante 2018
CSS
29
star
15

redux-spy

A higher order component decorator to read from a Redux store without subscribing to all its changes
JavaScript
29
star
16

reactalicante2017

Code used during my Redux Form talk at React Alicante 2017
CSS
26
star
17

react-callbag-listener

👂 A React render-prop component that listens to values emitted by callbags
JavaScript
21
star
18

tic-tac-toe-finite-state-machine

An exercise to build a tic-tac-toe finite state machine in typescript and xstate
TypeScript
17
star
19

callbag-pausable

⏯️ Callbag Pausable is a callbag that will convert any callbag stream into one that can be paused and resumed via data or talkback events.
JavaScript
10
star
20

react-thug

Silly React "Thug Life" meme image
10
star
21

postmessage-client-server

A simple promise-based client and server to communicate between pages and iframes with postmessage.
JavaScript
9
star
22

happyhourfm

Happy Hour with Dennis and Erik
TypeScript
6
star
23

expect-predicate

An extension for expect that lets you test values against arbitrary predicates
JavaScript
6
star
24

reactathon2020

Modern Forms in React workshop for Reactathon 2020
JavaScript
5
star
25

potionocean

TypeScript
5
star
26

javascript-flickr-badge

Javascript Flickr Badge
4
star
27

lemoncoders-20180502

Material de una clase he dado para Lemon Coders
JavaScript
4
star
28

seekjusticefm

Seek Justice Podcast
TypeScript
4
star
29

primatrix

If x is prime, is x + 30n prime?
TypeScript
3
star
30

callbag-types

Types for 👜 Callbags
JavaScript
3
star
31

reactfinland2020

JavaScript
2
star
32

typescript-react-apollo-example

Just demonstrating a problem... move along...
1
star
33

datocms-virtual-event-starter-kit-demo-8411

TypeScript
1
star
34

react-hot-loader-problem

A demonstration of a problem (bug?) in react-hot-loader
JavaScript
1
star
35

rescript-gentype-bug

Reproduction of a problem with Rescript's genType
TypeScript
1
star