1.0.2 β€’ Published 2 years ago

ducks v1.0.2

Weekly downloads
84
License
Apache-2.0
Repository
github
Last release
2 years ago

ducks

NPM Version NPM

πŸ¦†πŸ¦†πŸ¦† Ducks is A Redux Modular Proposal Implementation for Easily Managing and Using Your Ducks Reducer Bundle Packages.

Ducks

Image Credit: Alamy

Ducks Modular Proposal Re-Ducks Extended

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

  1. Implemented the specification from Ducks Modular Proposal, Erik Rasmussen, 2015
  2. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)
  3. Fully typing with all APIs by TypeScript
  4. Binding store to operators and selectors 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

Ducks Modular Proposal

The specification has rules that 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

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 Extension

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:

  1. MUST contain the entire logic for handling only ONE concept in your app, ex: product, cart, session, etc.
  2. MUST have an index.js file that exports according to the original duck rules.
  3. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.
  4. 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

  1. Perfrect TypeScript(v3.7) Typing Support powered by typesafe-actions.

  2. selectors...: Currying a State

  3. operators ... Currying a Dispatch
  4. namespaces...

  5. sagas...

  6. 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

  1. Node.js v12+
  2. 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

Links

Middlewares

Articles

Sagas

Relate Libraries

Related Projects

Resources

Concepts

Redux Ducks API compares with CQRS, Event Sourcing, and DDD:

DucksCQRSEvent SourcingDDD
actionsDomain Aggregates with Command handlers
- creatorCommand
- payloadEventEvent
selectorsQuery
operationsCommand + Event
middlewaresAggregate?Saga ?
types??
reducersReducers to calculate Aggregate state

reSolve

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)

/**

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\

Profile of Huan LI (ζŽε“ζ‘“) on StackOverflow

Copyright & License

  • Code & Docs Β© 2020 Huan LI (ζŽε“ζ‘“) \zixia@zixia.net\
  • Code released under the Apache-2.0 License
  • Docs released under Creative Commons
1.3.2

2 years ago

1.1.1

2 years ago

1.1.2

2 years ago

1.0.2

3 years ago

1.0.1

3 years ago

0.11.5

3 years ago

0.11.6

3 years ago

0.11.7

3 years ago

0.11.10

3 years ago

0.10.2

4 years ago

0.10.1

4 years ago

0.8.1

4 years ago

0.7.6

4 years ago

0.7.5

4 years ago

0.7.2

4 years ago

0.6.2

4 years ago

0.5.6

4 years ago

0.6.1

4 years ago

0.5.5

4 years ago

0.5.4

4 years ago

0.5.3

4 years ago

0.4.7

4 years ago

0.4.6

4 years ago

0.4.5

4 years ago

0.4.4

4 years ago

0.4.3

4 years ago

0.2.21

4 years ago

0.2.20

4 years ago

0.2.19

4 years ago

0.2.18

4 years ago

0.2.17

4 years ago

0.2.16

4 years ago

0.2.15

4 years ago

0.2.14

4 years ago

0.2.7

4 years ago

0.2.9

4 years ago

0.2.8

4 years ago

0.2.6

4 years ago

0.2.5

4 years ago

0.2.0

4 years ago

0.2.3

4 years ago

0.2.2

4 years ago

0.1.2

9 years ago

0.1.1

9 years ago

0.1.0

9 years ago