[
  {
    "path": "README.md",
    "content": "# Canonical Reducer Composition\n\n* [Spec](#spec)\n   * [Reducer Definition](#reducer-definition)\n   * [Domain](#domain)\n   * [Action](#action)\n* [Flux Standard Action](#flux-standard-action)\n* [`CONSTRUCT` Action Handler](#construct-action-handler)\n* [Schema](#schema)\n* [Implementation Example](#implementation-example)\n* [Benefits](#benefits)\n* [Redux Reducer Composition](#redux-reducer-composition)\n* [Validator Library](#validator-library)\n* [Libraries](#libraries)\n\n## Spec\n\nCanonical Reducer Composition pattern requires that:\n\n### Reducer Definition\n\n* Reducer definition **must** register at least one domain.\n* Action name **must** correspond to the action `name` property value.\n* Action name **must** be unique in the entire reducer definition object.\n\n### Domain\n\n* Domain **must** own only sub-domains or action handlers.\n* Domain **can** own another domain.\n* Domain **can** own action handlers.\n* Domain **can** own [`CONSTRUCT` action handler](#construct-action-handler).\n\n### Action Handler\n\n* Action handler **must** be a function.\n* Action handler **must** not mutate its arguments.\n* Action handler **must** return domain state.\n\n### Action\n\n* Action **must** be a plain object.\n* Action **must** define `name` property.\n    * Action `name` property value **must** be a string.\n    * Action `name` property value **must** consist only of uppercase latin characters and one or more underscore characters (`/^[A-Z\\_]+$/`).\n* Action **can** define `data` property. When defined,\n    * `data` property value **must** be a plain object.\n* Action **can** define `metadata` property. When defined, \n    * `metadata` property value **must** be a plain object.\n* Action **can** define `error` property. When defined,\n    * It **must** be an object.\n    * It **can** be an instance of [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error).\n    * It **must** have `message` property.\n    * `message` property value **must** be a string.\n\n## Flux Standard Action\n\n[Flux Standard Action](https://github.com/acdlite/flux-standard-action) (FSA) is a competing standard. If you are implementing software using Canonical Reducer Composition and have dependencies that use FSA convention, you can use [`redux-convention`](https://github.com/gajus/redux-convention) middleware to convert between the two standards.\n\n## `CONSTRUCT` Action Handler\n\n* A domain can register `CONSTRUCT` action handler.\n* `CONSTRUCT` can be used to construct the initial domain state.\n\nThe application must send `{name: 'CONSTRUCT'}` action to initialise the domain state, e.g.\n\n```js\nimport {\n    createStore\n} from 'redux';\n\nimport {\n     combineReducers\n} from 'redux-immutable';\n\nimport * as reducers from './reducers';\n\nimport Immutable from 'immutable';\n\nlet reducer,\n    state,\n    store;\n\nreducer = combineReducers(reducers);\n\nstate = Immutable.Map({});\n\n// Invoking CONSTRUCT to build the initial state.\nstate = reducer(state, {\n    name: 'CONSTRUCT'\n});\n\nstore = createStore(reducer, state);\n```\n\n## Schema\n\nReducer definition with a single domain:\n\n```js\n{\n    <domain>: {\n        <action handler> (domain, action) {\n\n        }\n    }\n}\n```\n\nIn addition, domain can define a sub-domain:\n\n```js\n{\n    <domain>: {\n        <domain>: {\n            /**\n             * Constructs the initial domain state.\n             * \n             * @param {Object} domain\n             * @return {Object}\n             */\n            CONSTRUCT (domain) {\n                \n            },\n            /**\n             * @typedef Action\n             * @see {@link https://github.com/gajus/canonical-reducer-composition#action}\n             * @property {String} name\n             */\n            \n            /**\n             * @param {Object} domain\n             * @param {Action} action\n             */\n            <action handler> (domain, action) {\n\n            },\n            <action handler> (domain, action) {\n\n            }\n        },\n        <domain>: {\n            <action handler> (domain, action) {\n\n            }\n        }\n    }\n}\n```\n\n## Benefits\n\nCanonical Reducer Composition has the following benefits:\n\n* Introduces reducer declaration convention.\n* Domain reducer function is called only if it registers an action.\n  * Enables logging of unhandled actions.\n* Enables intuitive nesting of the domain model.\n\n## Implementation Example\n\n```js\nimport {\n    createStore,\n} from 'redux';\n\nimport {\n    combineReducers\n} from 'redux-immutable';\n\nimport Immutable from 'immutable';\n\nlet reducer,\n    state,\n    store;\n\nstate = {\n    // <domain>\n    countries: [\n        'IT',\n        'JP',\n        'DE'\n    ],\n    // <domain>\n    cities: [],\n    // <domain>\n    user: {\n        // <domain>\n        names: [\n            'Gajus',\n            'Kuizinas'\n        ]\n    }\n}\n\nreducer = {\n    countries: {\n        ADD_COUNTRY: (domain, action) {\n            return domain.push(action.country);\n        },\n        REMOVE_COUNTRY: (domain, action) {\n            return domain.delete(domain.indexOf(action.country));\n        }\n    },\n    cities: {\n        // Using a constructor.\n        CONSTRUCT () {\n            return [\n                'Rome',\n                'Tokyo',\n                'Berlin'\n            ];\n        },\n        ADD_CITY (domain, action) {\n            return domain.push(action.city);\n        },\n        REMOVE_CITY (domain, action) {\n            return domain.delete(domain.indexOf(action.city));\n        }\n    },\n    // Implement a sub-domain reducer map.\n    user: {\n        names: {\n            ADD_NAME (domain, action) {\n                return domain.push(action.name);\n            },\n            REMOVE_NAME (domain, action) {\n                return domain.delete(domain.indexOf(action.name));\n            }\n        }\n    }\n};\n\nreducer = combineReducers(reducer);\n\nstate = Immutable.fromJS(state);\n// Invoking CONSTRUCT to build the initial state.\nstate = reducer(state, {\n    name: 'CONSTRUCT'\n});\n\nstore = createStore(reducer, state);\n```\n\n## Redux Reducer Composition\n\nRedux utilizes the concept of [reducer composition](http://gaearon.github.io/redux/docs/basics/Reducers.html#splitting-reducers).\n\n```js\nlet reducer = (state = {}, action) => ({\n    // <domain>: <domainReducer> (<domain data>, <action>)\n    countries: countryReducer(state.countries, action),\n    cities: cityReducer(state.cities, action)\n});\n```\n\nThe benefit of this pattern is that domain reducers do not need to know the complete state; domain reducers receive only part of the state for their domain. This enables better code separation.\n\nRedux [`combineReducers`](http://gaearon.github.io/redux/docs/api/combineReducers.html) is a helper that turns an object whose values are different reducing functions into a single reducing function.\n\n```js\nlet reducer = combineReducers({\n    countries: countryReducer,\n    cities: cityReducer\n});\n```\n\nHowever, Redux `combineReducers` does not dictate what should be the implementation of the domain reducer. Regardless of what is the implementation of the domain reducer, it does the same thing: listens to actions and when it recognizes an action, it create a new state, e.g.\n\n```js\nexport function countries (state = [], action) {\n    switch (action.type) {\n        case 'ADD_COUNTRY':\n            // state =\n            return state;\n\n        case 'REMOVE_COUNTRY':\n            // state =\n            return state;\n\n        default:\n            return state;\n    }\n}\n```\n\nThere are several problems with this:\n\n* This makes the code base less standardized (across different projects and different developers).\n* Domain reducer function is called regardless of whether it can handle the action.\n* The overhead of maintaining the boilerplate.\n\n## Validator Library\n\nLibraries that implement Canonical Reducer Composition pattern validation:\n\n* https://github.com/gajus/canonical-reducer-composition-validator\n\n## Libraries\n\nLibraries that implement Canonical Reducer Composition:\n\n* https://github.com/gajus/redux-immutable\n"
  }
]