{"_id":"redux-doghouse","_rev":"6-f051884410dde4f5c73f036f9202d9f7","name":"redux-doghouse","description":"Scoping helpers for building reusable components with Redux","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.0":{"name":"redux-doghouse","version":"1.0.0","description":"Scoping helpers for building reusable components with Redux","main":"lib/index.js","module":"es/index.js","jsnext:main":"es/index.js","files":["dist","lib","es","src"],"scripts":{"clean":"rimraf lib dist es","lint":"eslint src","test":"echo \"Error: no test specified\" && exit 1","prepublish":"npm run clean && npm run build","build":"npm run build:commonjs && npm run build:umd && npm run build:umd:min && npm run build:es","build:es":"cross-env BABEL_ENV=es babel src --out-dir es","build:commonjs":"cross-env BABEL_ENV=commonjs babel src --out-dir lib","build:umd":"cross-env BABEL_ENV=commonjs NODE_ENV=development webpack","build:umd:min":"cross-env BABEL_ENV=commonjs NODE_ENV=production webpack","counters":"cross-env BABEL_ENV=examples babel-node examples/counters/server.js"},"repository":{"type":"git","url":"git+https://github.com/DataDog/redux-doghouse.git"},"keywords":["redux","scope","doghouse","react"],"author":{"name":"Datadog","email":"dev@datadog.com","url":"http://www.datadog.com"},"contributors":[{"name":"Zacqary Adam Xeper","email":"zacqary@datadog.com","url":"https://github.com/zacqary"}],"license":"MIT","peerDependencies":{"redux":"3.x"},"devDependencies":{"autoprefixer":"6.5.0","babel-cli":"6.16.0","babel-eslint":"7.0.0","babel-loader":"6.2.5","babel-preset-es2015":"6.16.0","babel-preset-react":"6.16.0","babel-preset-stage-3":"6.17.0","cross-env":"3.1.1","css-loader":"0.25.0","eslint":"3.7.1","eslint-plugin-react":"6.4.1","postcss-loader":"0.13.0","react":"15.3.2","react-dom":"15.3.2","react-redux":"4.4.5","redux":"3.6.0","style-loader":"0.13.1","webpack-dev-middleware":"1.8.4","webpack-hot-middleware":"2.13.0"},"gitHead":"882a323ce1407cba6a3ec5ec3a2ed27f2287ccf6","bugs":{"url":"https://github.com/DataDog/redux-doghouse/issues"},"homepage":"https://github.com/DataDog/redux-doghouse#readme","_id":"redux-doghouse@1.0.0","_shasum":"986376091fa5392472490190f68890c01e3caf66","_from":".","_npmVersion":"3.10.8","_nodeVersion":"7.0.0","_npmUser":{"name":"datadog","email":"package@datadoghq.com"},"dist":{"shasum":"986376091fa5392472490190f68890c01e3caf66","tarball":"https://registry.npmjs.org/redux-doghouse/-/redux-doghouse-1.0.0.tgz","integrity":"sha512-Ee9qEnSgKJBCZKb4v2N2ed8MLWZ6m0/Z4ThW+kOEMqHpeCJN+NDCylLD5ZBPOOYs3mchEqlRjJ22HBiKqoPVLw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCiOjn6ut3sIK88h/w27NPf8fKB4yNi7EaPMnxUr96bkgIhANtAKtn5PZEFOf1ZsoEJTNSK/PotPLQWdG5b/B0qm4CJ"}]},"maintainers":[{"name":"datadog","email":"package@datadoghq.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/redux-doghouse-1.0.0.tgz_1478809043708_0.22623567329719663"}},"1.0.2":{"name":"redux-doghouse","version":"1.0.2","description":"Scoping helpers for building reusable components with Redux","main":"lib/index.js","module":"es/index.js","jsnext:main":"es/index.js","files":["dist","lib","es","src"],"scripts":{"clean":"rimraf lib dist es","lint":"eslint src","test":"cross-env BABEL_ENV=commonjs jest","check:src":"npm run lint && npm run test","prepublish":"npm run clean && npm run check:src && npm run build","build":"npm run build:commonjs && npm run build:umd && npm run build:umd:min && npm run build:es","build:es":"cross-env BABEL_ENV=es babel src --out-dir es","build:commonjs":"cross-env BABEL_ENV=commonjs babel src --out-dir lib","build:umd":"cross-env BABEL_ENV=commonjs NODE_ENV=development webpack","build:umd:min":"cross-env BABEL_ENV=commonjs NODE_ENV=production webpack","counters":"cross-env BABEL_ENV=examples babel-node examples/counters/server.js"},"repository":{"type":"git","url":"git+https://github.com/DataDog/redux-doghouse.git"},"keywords":["redux","scope","doghouse","react"],"author":{"name":"Datadog","email":"dev@datadog.com","url":"http://www.datadog.com"},"contributors":[{"name":"Zacqary Adam Xeper","email":"zacqary@datadog.com","url":"https://github.com/zacqary"}],"license":"MIT","peerDependencies":{"redux":"3.x"},"devDependencies":{"autoprefixer":"6.5.0","babel-cli":"6.16.0","babel-eslint":"7.0.0","babel-loader":"6.2.5","babel-preset-es2015":"6.16.0","babel-preset-react":"6.16.0","babel-preset-stage-3":"6.17.0","cross-env":"3.1.1","css-loader":"0.25.0","eslint":"3.7.1","eslint-plugin-react":"6.4.1","express":"^4.14.0","jest":"17.0.3","postcss-loader":"0.13.0","react":"15.3.2","react-dom":"15.3.2","react-redux":"4.4.5","redux":"3.6.0","style-loader":"0.13.1","webpack":"^1.13.3","webpack-dev-middleware":"1.8.4","webpack-hot-middleware":"2.13.0"},"jest":{"testRegex":"(/test/.*\\.spec.js)$"},"gitHead":"a9082292ea420cc89f0121876832cb713aad8438","bugs":{"url":"https://github.com/DataDog/redux-doghouse/issues"},"homepage":"https://github.com/DataDog/redux-doghouse#readme","_id":"redux-doghouse@1.0.2","_shasum":"f1fe639ccdbc0342abd106f5f561e5db894187d8","_from":".","_npmVersion":"3.10.8","_nodeVersion":"7.0.0","_npmUser":{"name":"datadog","email":"package@datadoghq.com"},"dist":{"shasum":"f1fe639ccdbc0342abd106f5f561e5db894187d8","tarball":"https://registry.npmjs.org/redux-doghouse/-/redux-doghouse-1.0.2.tgz","integrity":"sha512-UJgEmbNDGmYh//JlHAeZnAZZvIUe+ae8A7JegMR8ULoPUyKu8ThkGwUWWf/qaNDrEw47IYllxS4u5RgynHmTJA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFc45aS9hXdFOATIXmlLkeQYn+p4xKSB4XNTCssuRP/PAiBSVfsSf9cMIfnqUDvbDxhGBo2pch03uain+Q8KJAu1yQ=="}]},"maintainers":[{"name":"datadog","email":"package@datadoghq.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/redux-doghouse-1.0.2.tgz_1479850126019_0.041460561798885465"}}},"readme":"# redux-doghouse\n\n`redux-doghouse` is a library that aims to make **reusable components** easier to build with Redux by **scoping actions and reducers** to a particular instance of a component.\n\n![A diagram of how Redux-Doghouse works](doghousediagram.png)\n\nIt includes tools to help you build **Scoped Actions** and **Scoped Reducers** with minimal modifications to your code. That way, if you build a Redux store for a `Parent` with an **arbitrary number** of `Children` (meaning there can be none, one, or a million of them), actions affecting `Child A` won't affect `Child B` through `Child Z`.\n\n**You can read more about why we built `redux-doghouse`, and our real-world use-case, in this [blog post](http://engineering.datadoghq.com/redux-doghouse--creating-reusable-react-redux-components-through-scoping/).**\n\n# Getting Started\n## Installation\n```\nnpm install redux-doghouse\n```\n\n## Running Examples\n### Counters ([Live Demo](https://redux-doghouse-example.now.sh/))\nAn app that renders an arbitrary number of `<Counter>`s, with the ability to change the value of one of them at a time, all of them at once, or only the ones with even or odd numbers\n```\nnpm run counters\n```\n\n# API\n1. [scopeActionCreators](#scopeactioncreatorsactioncreators-scopeID)\n2. [ScopedActionFactory](#scopedactionfactoryactioncreators)\n3. [bindScopedActionFactories](#bindscopedactionfactoriesactionfactories-dispatch-bindfn)\n4. [bindActionCreatorsDeep](#bindactioncreatorsdeepactioncreatortree-dispatch)\n5. [scopeReducers](#scopereducersreducers)\n\n## For Actions\n### `scopeActionCreators(actionCreators, scopeID)`\nAdds a scope to the output of a set of action creators\n\nThe `actionCreators` should be in the same format that you would pass to `bindActionCreators`. e.g:\n```javascript\n(value) => ({type: SET_FOO, value})\n```\nor\n```javascript\n{\n    foo: (value) => ({type: SET_FOO, value})\n}\n```\nIt will then **scope** each of these action creators, so that the resulting action will include the `scopeID`.\n```javascript\n{\n    foo: (value) => ({\n        type: SET_FOO, value,\n        scopeID: \"[the specified scopeID]\"\n    })\n}\n```\n\n#### Arguments\n - `actionCreators` *(Function or Object)*: An action creator, or an object whose values are action creators. The values can also be nested objects whose values are action creators (or more nested objects, and so on).\n- `scopeID` *(String or Number)*: An identifier to include in any actions created by the `actionCreators`\n\n#### Returns\n\n*(Object or Function)*: An object mimicking the original object, but with each function adding `{ scopeID }` to the *Object* that they return. If you passed a function as `actionCreators`, the return value will also be a single function.\n\n#### Example\n```javascript\nimport { scopeActionCreators } from 'redux-doghouse';\nimport { actionCreators } from './my-actions';\n\n// Before scoping:\nactionCreators.foo('bar');\n// Will return\n{\n    type: 'SET_FOO',\n    value: 'bar'\n};\n/// After scoping:\nscopeActionCreators(actionCreators, 'a').foo('bar')\n// Will return\n{\n    type: 'SET_FOO',\n    value: 'bar',\n    scopeID: 'a'\n}\n```\n\n### `ScopedActionFactory(actionCreators)`\nWorks similarly to `scopeActionCreators`, but with the added benefit of `instanceof` checking. This allows you to write a check to see whether or not a set of action creators is an `instanceof ScopedActionFactory`.\n\nFor example, the included `bindActionCreatorsDeep` function will intelligently bind an object tree of both scoped and un-scoped action creators, depending on whether it's passed plain objects or `ScopedActionFactory` instances.\n\n#### Arguments\n- `actionCreators` *(Function or Object)*: An action creator, or an object whose values are action creators\n\n#### Returns\n\n*(ScopedActionFactory)* A class of object with the following:\n\n##### Instance Methods\n###### `scope(id): Object`\nRuns `scopeActionCreators(id)` on the `actionCreators` that were passed to the `new ScopeActionFactory`, and returns the result.\n\n#### Example\n```javascript\nimport { ScopedActionFactory } from 'redux-doghouse';\nimport { actionCreators } from './my-actions';\n\nconst scopeableActions = new ScopedActionFactory(actionCreators);\nconst actionCreatorsScopedToA = scopeableActions.scope('a');\nconst actionCreatorsScopedToB = scopeableActions.scope('b');\n\nactionCreatorsScopedToA.foo('bar')\n// Will return\n{\n    type: SET_FOO,\n    value: 'bar',\n    scopeID: 'a'\n}\n```\n\n### `bindScopedActionFactories(actionFactories, dispatch, [bindFn])`\nTakes an object of `actionFactories` and binds them all to a `dispatch` function. By default, it will use Redux's included `bindActionCreators` to do this, but you can specify a `bindFn` to use instead.\n\n#### Arguments\n- `actionFactories` *(Object or ScopedActionFactory)*: A single ScopedActionFactory, or an object whose values are ScopedActionFactories.\n- `dispatch` *(Function)*: A function to which the resulting action creators from `actionFactories` should be dispatched; usually this is the `dispatch` method of a Redux store\n- [`bindFn`] *(Function)*: If specified, this function will be used to bind resulting action creators to the `dispatch`. If unspecified, Redux's native `bindActionCreators` will be used by default.\n\n#### Returns\n*(Object or ScopedActionFactory)*: An object mimicking the original object, but with each `ScopedActionFactory` generating functions that will immediately dispatch the action returned by the corresponding action creator. If you passed a single factory as `actionFactories`, the return value will also be a single factory.\n\n#### Example\n```javascript\nimport { createStore } from 'redux';\nimport { ScopedActionFactory, bindScopedActionFactories } from 'redux-doghouse';\nimport { actionCreators, reducers } from './my-redux-component';\n\nconst store = createStore(reducers);\nconst scopeableActions = {\n    myComponentActions: new ScopedActionFactory(actionCreators);\n}\nconst boundScopeableActions = bindScopedActionFactories(scopeableActions, store.dispatch);\n```\n\n### `bindActionCreatorsDeep(actionCreatorTree, dispatch)`\nExtends Redux's native `bindActionCreators` to allow you to bind a whole tree of nested action creator `function`s and `ScopedActionFactory` instances to a `dispatch` function.\n\n#### Arguments\n- `actionCreatorTree` *(Object)*: An object whose values can be:\n    - A *Function* to be bound to the `dispatch`\n    - A `ScopedActionFactory` to be bound to the `dispatch`\n    - Another *Object* containing either of these (or more nested *Object*)\n- `dispatch` *(Function)*: A function to which the members of `actionCreatorTree` should be dispatched; usually this is the `dispatch` method of a Redux store\n\n#### Example\n```javascript\nimport { bindActionCreatorsDeep, ScopedActionFactory } from 'redux-doghouse';\nimport { createStore } from 'redux';\nimport { reducers } from './my-reducers';\n\nconst store = createStore(reducers);\n\nconst actionCreators = {\n    fooActions: {\n        bar: (value) => ({type: 'BAR', value})\n    },\n    barActions: {\n        baz: new ScopedActionFactory({\n            quux: (value) => ({type: 'QUUX'})\n        })\n    }\n}\nconst boundActionCreators = bindActionCreatorsDeep(boundActionCreators, store.dispatch);\n```\n\n## For Reducers\n\n### `scopeReducers(reducers)`\nThis acts as an extension of Redux's `combineReducers`, which takes an object of `reducers` in the form of `{ [prop]: reducer(state, action) }` pairs and combines them into a single reducer that returns `{ [prop]: state }` pairs. `scopeReducers` goes a step further and returns an object of `{ [scopeID]: { [prop]: state} }` pairs.\n\nIn other words, it will create a reference to your `reducers` for each new `scopeID` you add to your data model, and route scoped actions to their corresponding `scopeID` when reducing a new state.\n\n#### Arguments\n- `reducers` *(Object)*: An object whose keys correspond to property names, and whose values correspond to different reducing functions that need to be combined into one and reused across multiple scopes.\n\n#### Returns\n*(Function)*: A reducer that takes an object of state objects in the form of `{ [scopeID]: state }` pairs, and an action that includes a `scopeID`. The reducer will return a new object mimicking the original object, but for each key:\n\n1. For the matching `scopeID`, invoke the `reducers` to construct a new state object with the same shape as the `reducers`\n2. Leave all the other `scopeID`s' state objects unchanged\n\n#### Example\n```javascript\n// Given these actionCreators...\nimport { scopeActionCreators } from 'redux-doghouse';\nconst reducers = {\n    foo: (state = 0, action) => {\n        switch (action.type) {\n            case 'INCREMENT_FOO':\n                return state + 1;\n            case 'DECREMENT_FOO':\n                return state - 1;\n            default:\n                return state;\n        }\n    }\n};\nconst actionCreatorsA = scopeActionCreators({\n    incrementFoo: () => ({type: 'INCREMENT_FOO'})\n}, 'a');\n\n// Without scoping\nimport { combineReducers } from 'redux';\nconst combinedReducers = combineReducers(reducers);\nconst state = {foo: 0};\ncombinedReducers(state, actionCreatorsA.incrementFoo());\n// Will return\n{foo: 1}\n\n// With scoping\nimport { scopeReducers } from 'redux-doghouse';\nconst scopedReducers = scopeReducers(reducers);\nconst state = {\n    a: {foo: 0},\n    b: {foo: 2}\n};\nscopedReducers(state, actionCreatorsA.incrementFoo());\n// Will return\n{\n    a: {foo: 1},\n    b: {foo: 2}\n}\n```\n","maintainers":[{"name":"datadog","email":"package@datadoghq.com"}],"time":{"modified":"2022-06-26T10:06:19.948Z","created":"2016-11-10T20:17:24.331Z","1.0.0":"2016-11-10T20:17:24.331Z","1.0.1":"2016-11-22T21:20:43.042Z","1.0.2":"2016-11-22T21:28:46.714Z"},"homepage":"https://github.com/DataDog/redux-doghouse#readme","keywords":["redux","scope","doghouse","react"],"repository":{"type":"git","url":"git+https://github.com/DataDog/redux-doghouse.git"},"contributors":[{"name":"Zacqary Adam Xeper","email":"zacqary@datadog.com","url":"https://github.com/zacqary"}],"author":{"name":"Datadog","email":"dev@datadog.com","url":"http://www.datadog.com"},"bugs":{"url":"https://github.com/DataDog/redux-doghouse/issues"},"license":"MIT","readmeFilename":"README.md"}