ducks v1.0.2
ducks
π¦π¦π¦ Ducks is A Redux Modular Proposal Implementation for Easily Managing and Using Your Ducks Reducer Bundle Packages.
Image Credit: Alamy
Ducks offers a method of handling redux module packaging, installing, and running with your Redux store, with middware support. The goal of Ducks is to help you organizing your code for the long term.
Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles "ducks", as in the last syllable of "redux".
β Erik Rasmussen, 2015 (link)
Features
- Implemented the specification from Ducks Modular Proposal, Erik Rasmussen, 2015
- Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)
- Fully typing with all APIs by TypeScript
- Binding
store
tooperators
andselectors
by currying for maximum convenience.
Todo-list
- Ducks middleware support
- Provides a Ducks Management interface for adding/deleting a duck module
Motivation
I'm building my redux ducks module for Wechaty Redux project and ...
The Ducks Modular Proposal
The specification has rules that a module...
- MUST
export default
a function calledreducer()
- MUST
export
its action creators as functions - MUST have action types in the form
npm-module-or-app/reducer/ACTION_TYPE
- 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
Here's the full version of Ducks proposal: Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015
The Re-Ducks Extionsion: Duck Folders
Re-Ducks
is an extension to the original proposal for the ducks redux modular architecture.
By defining a ducks with duck folders instead of a duck file, it defines the duck folder would like:
duck/
βββ actions.js
βββ index.js
βββ operations.js
βββ reducers.js
βββ selectors.js
βββ tests.js
βββ types.js
βββ utils.js
NOTE: Each concept from your app will have a similar folder.
General rules for a duck folder
A duck folder:
- MUST contain the entire logic for handling only ONE concept in your app, ex: product, cart, session, etc.
- MUST have an
index.js
file that exports according to the original duck rules. - MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.
- MUST contain the tests related to the duck.
Here's the full version of Re-ducks proposal: Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016 and blog
Extensions
Perfrect TypeScript(v3.7) Typing Support powered by typesafe-actions.
selectors...: Currying a State
- operators ... Currying a Dispatch
namespaces...
sagas...
- epics...
nesting ducks?
Ducks++ is to define a string constant inside the duck to determine where the state is stored in the store; Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017
Requirements
- Node.js v12+
- Browsers
Usage
1 Setup Ducks
export const types = { TAP: 'ducks/examples/counter/TAP' }
export const actions = { tap: () => ({ type: TAP }) }
export const operations = { tap: dispatch => dispatch(actions.tap()) }
export const selectors = { getTotal: state => () => state.total }
const initialState = { total: 0 }
export default function reducer (state = initialState, action) {
if (action.type === types.TAP) {
return ({
...state,
total: (state.total || 0) + 1,
})
}
}
2 Load Ducks
import { Ducks, Duck } from 'ducks'
import { CounterDuckAPI } from 'ducks/examples/counter/'
const counter = new Duck(CounterDuckAPI)
const ducks = new Ducks({ counter })
3 Create Store
import { createStore } from 'redux'
const store = createStore(
state => state, // Your other reducers
ducks.enhancer(), // Add ducks to your store (that's all you need to do!)
)
You are set!
A full example that demostrate how to use Ducks can be found at examples/quack.ts, you can try it by running the following commands:
git clone git@github.com:huan/ducks.git
cd ducks
npm install
npm start
API References
3.1 Shortcut to Configure the Store
If you only use Redux with Ducks, then you can use the shortcut from the Ducks to get the configured store:
const store = ducks.getStore()
The ducks.getStore()
will do exact the same as the above createStore()
codes.
References
in compose()
, ducks.enhancer()
must be put before applyMiddleware
ducks.enhancer(),
applyMiddleware(
reduceReducersFromMapObject
We planed to directly use reduce-reducers before, however it does not support types well. The
ReturnType
of it can not reflect the data type of the reducer returned state.
Inspired from https://github.com/redux-utilities/reduce-reducers/
Knowned Issues: https://stackoverflow.com/a/44371190/1123955
const addAndMult = reduceReducers(reducerAdd, reducerMult)
const initial = addAndMult(undefined)
/*
* {
* sum: 0,
* totalOperations: 0
* }
*
* First, reducerAdd is called, which gives us initial state { sum: 0 }
* Second, reducerMult is called, which doesn't have payload, so it
* just returns state unchanged.
* That's why there isn't any `product` prop.
*/
Developing Tools
- Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture
- Conditional Type Checks
Links
- Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018
- Redux: Another implementation for Selector Pattern
- Scaling your Redux App with ducks
- Where do I put my business logic in a React-Redux application?
- Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities
Middlewares
- ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.
- Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares
- Redux Middleware Lifecycle - Impure and asynchronous; but still redux(https://hackernoon.com/
- Understanding Redux Middleware
- You Arenβt Using Redux Middleware Enough
- redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically
Articles
- Modular Reducers and Selectors
- Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability redux-middleware-lifecycle-7d8defa4db7e)
- reSolve - A Redux-Inspired Backend
Sagas
- This collection of common Redux-saga patterns will make your life easier.
- Lost with Redux and sagas? Implement them yourself!
Relate Libraries
- redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion
- redux-dynamic-modules - Modularize Redux by dynamically loading reducers and middlewares.
- Dynamically inject reducers in your react reduc app. HMR and SSR compatible.
- Helper for loading sagas asynchronously using redux
- π inject reducer and saga anywhere in the application.
- Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty
- Allows dynamically injecting reducers into a redux store at runtime
- redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates
- Reduce Reducers - Reduce multiple reducers into a single reducer from left to right
- Utilities that embrace best practices while working with redux in a universal application.
- createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.
- Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)
- Composable ducklings
- Factory for simple creation and use of redux ducks.
- tiny-duck - Composable redux reducers
- reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.
Related Projects
Resources
Concepts
Redux Ducks API compares with CQRS, Event Sourcing, and DDD:
Ducks | CQRS | Event Sourcing | DDD |
---|---|---|---|
actions | Domain Aggregates with Command handlers | ||
- creator | Command | ||
- payload | Event | Event | |
selectors | Query | ||
operations | Command + Event | ||
middlewares | Aggregate? | Saga ? | |
types | ?? | ||
reducers | Reducers to calculate Aggregate state |
DDD (Domain Driven Design)
Domain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.
ES (Event Sourcing()
Don't store system state, store events that brought system to this state.
CQRS (Command Query Responsibility Segregation)
/**
- CQRS - Command Query Responsibility Segregation
- https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs
operations
for Command
selectors
for Query */
System is divided in two "sides":
- Write Side accepts commands and generate events that stored in the Event Store.
- Read Side applies events to Read Models, and process queries.
History
master
v0.2 (May 2020)
Thanks @gobwas for letting me use this great NPM module name ducks
for my project, Appreciate it!
Author
Huan LI (ζεζ‘) Microsoft Regional Director \zixia@zixia.net\
Copyright & License
- Code & Docs Β© 2020 Huan LI (ζεζ‘) \zixia@zixia.net\
- Code released under the Apache-2.0 License
- Docs released under Creative Commons
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
9 years ago
9 years ago
9 years ago