├── .babelrc ├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── .nyc_output ├── 022f543c-edba-469a-8460-52a3a3a0724c.json ├── 0b94db04-251f-4ce1-9a43-745d3913961a.json └── processinfo │ ├── 022f543c-edba-469a-8460-52a3a3a0724c.json │ ├── 0b94db04-251f-4ce1-9a43-745d3913961a.json │ └── index.json ├── .prettierrc ├── .travis.yml ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── index.js └── spec.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ], 5 | "plugins": [ 6 | "@babel/plugin-proposal-object-rest-spread" 7 | ] 8 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: rwieruch 4 | patreon: # rwieruch 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with a single custom sponsorship URL 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logfile 2 | 3 | .env 4 | 5 | node_modules/ 6 | lib/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ -------------------------------------------------------------------------------- /.nyc_output/022f543c-edba-469a-8460-52a3a3a0724c.json: -------------------------------------------------------------------------------- 1 | {"/Users/mydspr/Developer/Repos/use-combined-reducers/src/spec.js":{"path":"/Users/mydspr/Developer/Repos/use-combined-reducers/src/spec.js","statementMap":{"0":{"start":{"line":3,"column":12},"end":{"line":3,"column":27}},"1":{"start":{"line":5,"column":13},"end":{"line":5,"column":29}},"2":{"start":{"line":7,"column":8},"end":{"line":7,"column":45}},"3":{"start":{"line":9,"column":39},"end":{"line":9,"column":95}},"4":{"start":{"line":11,"column":34},"end":{"line":11,"column":117}},"5":{"start":{"line":13,"column":30},"end":{"line":13,"column":106}},"6":{"start":{"line":15,"column":52},"end":{"line":15,"column":54}},"7":{"start":{"line":15,"column":65},"end":{"line":15,"column":69}},"8":{"start":{"line":15,"column":80},"end":{"line":15,"column":85}},"9":{"start":{"line":15,"column":96},"end":{"line":15,"column":105}},"10":{"start":{"line":15,"column":107},"end":{"line":15,"column":394}},"11":{"start":{"line":15,"column":113},"end":{"line":15,"column":256}},"12":{"start":{"line":15,"column":127},"end":{"line":15,"column":149}},"13":{"start":{"line":15,"column":199},"end":{"line":15,"column":219}},"14":{"start":{"line":15,"column":220},"end":{"line":15,"column":254}},"15":{"start":{"line":15,"column":248},"end":{"line":15,"column":254}},"16":{"start":{"line":15,"column":273},"end":{"line":15,"column":283}},"17":{"start":{"line":15,"column":284},"end":{"line":15,"column":293}},"18":{"start":{"line":15,"column":306},"end":{"line":15,"column":392}},"19":{"start":{"line":15,"column":312},"end":{"line":15,"column":360}},"20":{"start":{"line":15,"column":345},"end":{"line":15,"column":360}},"21":{"start":{"line":15,"column":373},"end":{"line":15,"column":390}},"22":{"start":{"line":15,"column":381},"end":{"line":15,"column":390}},"23":{"start":{"line":15,"column":395},"end":{"line":15,"column":407}},"24":{"start":{"line":17,"column":32},"end":{"line":17,"column":67}},"25":{"start":{"line":17,"column":56},"end":{"line":17,"column":67}},"26":{"start":{"line":19,"column":0},"end":{"line":52,"column":3}},"27":{"start":{"line":20,"column":2},"end":{"line":33,"column":5}},"28":{"start":{"line":21,"column":31},"end":{"line":24,"column":6}},"29":{"start":{"line":25,"column":32},"end":{"line":25,"column":71}},"30":{"start":{"line":26,"column":16},"end":{"line":26,"column":40}},"31":{"start":{"line":27,"column":19},"end":{"line":27,"column":43}},"32":{"start":{"line":29,"column":4},"end":{"line":32,"column":7}},"33":{"start":{"line":34,"column":2},"end":{"line":51,"column":5}},"34":{"start":{"line":35,"column":20},"end":{"line":35,"column":37}},"35":{"start":{"line":36,"column":20},"end":{"line":36,"column":37}},"36":{"start":{"line":38,"column":32},"end":{"line":41,"column":6}},"37":{"start":{"line":42,"column":32},"end":{"line":42,"column":72}},"38":{"start":{"line":43,"column":16},"end":{"line":43,"column":40}},"39":{"start":{"line":44,"column":19},"end":{"line":44,"column":43}},"40":{"start":{"line":46,"column":4},"end":{"line":48,"column":7}},"41":{"start":{"line":49,"column":4},"end":{"line":49,"column":57}},"42":{"start":{"line":50,"column":4},"end":{"line":50,"column":57}}},"fnMap":{"0":{"name":"_interopRequireDefault","decl":{"start":{"line":9,"column":9},"end":{"line":9,"column":31}},"loc":{"start":{"line":9,"column":37},"end":{"line":9,"column":97}},"line":9},"1":{"name":"_slicedToArray","decl":{"start":{"line":11,"column":9},"end":{"line":11,"column":23}},"loc":{"start":{"line":11,"column":32},"end":{"line":11,"column":119}},"line":11},"2":{"name":"_nonIterableRest","decl":{"start":{"line":13,"column":9},"end":{"line":13,"column":25}},"loc":{"start":{"line":13,"column":28},"end":{"line":13,"column":108}},"line":13},"3":{"name":"_iterableToArrayLimit","decl":{"start":{"line":15,"column":9},"end":{"line":15,"column":30}},"loc":{"start":{"line":15,"column":39},"end":{"line":15,"column":409}},"line":15},"4":{"name":"_arrayWithHoles","decl":{"start":{"line":17,"column":9},"end":{"line":17,"column":24}},"loc":{"start":{"line":17,"column":30},"end":{"line":17,"column":69}},"line":17},"5":{"name":"(anonymous_5)","decl":{"start":{"line":19,"column":31},"end":{"line":19,"column":32}},"loc":{"start":{"line":19,"column":43},"end":{"line":52,"column":1}},"line":19},"6":{"name":"(anonymous_6)","decl":{"start":{"line":20,"column":54},"end":{"line":20,"column":55}},"loc":{"start":{"line":20,"column":66},"end":{"line":33,"column":3}},"line":20},"7":{"name":"(anonymous_7)","decl":{"start":{"line":22,"column":15},"end":{"line":22,"column":16}},"loc":{"start":{"line":22,"column":27},"end":{"line":22,"column":29}},"line":22},"8":{"name":"(anonymous_8)","decl":{"start":{"line":23,"column":15},"end":{"line":23,"column":16}},"loc":{"start":{"line":23,"column":27},"end":{"line":23,"column":29}},"line":23},"9":{"name":"(anonymous_9)","decl":{"start":{"line":34,"column":76},"end":{"line":34,"column":77}},"loc":{"start":{"line":34,"column":88},"end":{"line":51,"column":3}},"line":34}},"branchMap":{"0":{"loc":{"start":{"line":9,"column":46},"end":{"line":9,"column":94}},"type":"cond-expr","locations":[{"start":{"line":9,"column":70},"end":{"line":9,"column":73}},{"start":{"line":9,"column":76},"end":{"line":9,"column":94}}],"line":9},"1":{"loc":{"start":{"line":9,"column":46},"end":{"line":9,"column":67}},"type":"binary-expr","locations":[{"start":{"line":9,"column":46},"end":{"line":9,"column":49}},{"start":{"line":9,"column":53},"end":{"line":9,"column":67}}],"line":9},"2":{"loc":{"start":{"line":11,"column":41},"end":{"line":11,"column":116}},"type":"binary-expr","locations":[{"start":{"line":11,"column":41},"end":{"line":11,"column":61}},{"start":{"line":11,"column":65},"end":{"line":11,"column":94}},{"start":{"line":11,"column":98},"end":{"line":11,"column":116}}],"line":11},"3":{"loc":{"start":{"line":15,"column":220},"end":{"line":15,"column":254}},"type":"if","locations":[{"start":{"line":15,"column":220},"end":{"line":15,"column":254}},{"start":{"line":15,"column":220},"end":{"line":15,"column":254}}],"line":15},"4":{"loc":{"start":{"line":15,"column":224},"end":{"line":15,"column":246}},"type":"binary-expr","locations":[{"start":{"line":15,"column":224},"end":{"line":15,"column":225}},{"start":{"line":15,"column":229},"end":{"line":15,"column":246}}],"line":15},"5":{"loc":{"start":{"line":15,"column":312},"end":{"line":15,"column":360}},"type":"if","locations":[{"start":{"line":15,"column":312},"end":{"line":15,"column":360}},{"start":{"line":15,"column":312},"end":{"line":15,"column":360}}],"line":15},"6":{"loc":{"start":{"line":15,"column":316},"end":{"line":15,"column":343}},"type":"binary-expr","locations":[{"start":{"line":15,"column":316},"end":{"line":15,"column":319}},{"start":{"line":15,"column":323},"end":{"line":15,"column":343}}],"line":15},"7":{"loc":{"start":{"line":15,"column":373},"end":{"line":15,"column":390}},"type":"if","locations":[{"start":{"line":15,"column":373},"end":{"line":15,"column":390}},{"start":{"line":15,"column":373},"end":{"line":15,"column":390}}],"line":15},"8":{"loc":{"start":{"line":17,"column":32},"end":{"line":17,"column":67}},"type":"if","locations":[{"start":{"line":17,"column":32},"end":{"line":17,"column":67}},{"start":{"line":17,"column":32},"end":{"line":17,"column":67}}],"line":17}},"s":{"0":1,"1":1,"2":1,"3":1,"4":2,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":2,"25":2,"26":1,"27":1,"28":1,"29":1,"30":1,"31":1,"32":1,"33":1,"34":1,"35":1,"36":1,"37":1,"38":1,"39":1,"40":1,"41":1,"42":1},"f":{"0":1,"1":2,"2":0,"3":0,"4":2,"5":1,"6":1,"7":0,"8":0,"9":1},"b":{"0":[1,0],"1":[1,1],"2":[2,0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[2,0]},"_coverageSchema":"43e27e138ebf9cfc5966b082cf9a028302ed4184","hash":"b3e2071bb0acb231058ee76337d03589476c0d37","contentHash":"1151b240290cabbd0636a21de188cd2bb31c5523df86b87bf14513f988a92b70"},"/Users/mydspr/Developer/Repos/use-combined-reducers/src/index.js":{"path":"/Users/mydspr/Developer/Repos/use-combined-reducers/src/index.js","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":5,"column":3}},"1":{"start":{"line":6,"column":0},"end":{"line":6,"column":28}},"2":{"start":{"line":8,"column":33},"end":{"line":8,"column":464}},"3":{"start":{"line":8,"column":46},"end":{"line":8,"column":47}},"4":{"start":{"line":8,"column":91},"end":{"line":8,"column":131}},"5":{"start":{"line":8,"column":147},"end":{"line":8,"column":166}},"6":{"start":{"line":8,"column":168},"end":{"line":8,"column":382}},"7":{"start":{"line":8,"column":226},"end":{"line":8,"column":380}},"8":{"start":{"line":8,"column":312},"end":{"line":8,"column":375}},"9":{"start":{"line":8,"column":383},"end":{"line":8,"column":462}},"10":{"start":{"line":8,"column":416},"end":{"line":8,"column":458}},"11":{"start":{"line":8,"column":465},"end":{"line":8,"column":479}},"12":{"start":{"line":10,"column":44},"end":{"line":10,"column":195}},"13":{"start":{"line":10,"column":62},"end":{"line":10,"column":166}},"14":{"start":{"line":10,"column":176},"end":{"line":10,"column":193}},"15":{"start":{"line":10,"column":196},"end":{"line":10,"column":207}},"16":{"start":{"line":12,"column":26},"end":{"line":27,"column":1}},"17":{"start":{"line":14,"column":14},"end":{"line":16,"column":8}},"18":{"start":{"line":15,"column":4},"end":{"line":15,"column":86}},"19":{"start":{"line":18,"column":17},"end":{"line":24,"column":3}},"20":{"start":{"line":19,"column":4},"end":{"line":23,"column":7}},"21":{"start":{"line":20,"column":6},"end":{"line":20,"column":38}},"22":{"start":{"line":22,"column":6},"end":{"line":22,"column":24}},"23":{"start":{"line":26,"column":2},"end":{"line":26,"column":27}},"24":{"start":{"line":29,"column":15},"end":{"line":29,"column":34}},"25":{"start":{"line":30,"column":0},"end":{"line":30,"column":30}}},"fnMap":{"0":{"name":"_objectSpread","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":22}},"loc":{"start":{"line":8,"column":31},"end":{"line":8,"column":481}},"line":8},"1":{"name":"(anonymous_1)","decl":{"start":{"line":8,"column":295},"end":{"line":8,"column":296}},"loc":{"start":{"line":8,"column":310},"end":{"line":8,"column":377}},"line":8},"2":{"name":"(anonymous_2)","decl":{"start":{"line":8,"column":399},"end":{"line":8,"column":400}},"loc":{"start":{"line":8,"column":414},"end":{"line":8,"column":460}},"line":8},"3":{"name":"_defineProperty","decl":{"start":{"line":10,"column":9},"end":{"line":10,"column":24}},"loc":{"start":{"line":10,"column":42},"end":{"line":10,"column":209}},"line":10},"4":{"name":"useCombinedReducers","decl":{"start":{"line":12,"column":35},"end":{"line":12,"column":54}},"loc":{"start":{"line":12,"column":73},"end":{"line":27,"column":1}},"line":12},"5":{"name":"(anonymous_5)","decl":{"start":{"line":14,"column":51},"end":{"line":14,"column":52}},"loc":{"start":{"line":14,"column":71},"end":{"line":16,"column":3}},"line":14},"6":{"name":"dispatch","decl":{"start":{"line":18,"column":26},"end":{"line":18,"column":34}},"loc":{"start":{"line":18,"column":43},"end":{"line":24,"column":3}},"line":18},"7":{"name":"(anonymous_7)","decl":{"start":{"line":19,"column":45},"end":{"line":19,"column":46}},"loc":{"start":{"line":19,"column":60},"end":{"line":21,"column":5}},"line":19},"8":{"name":"(anonymous_8)","decl":{"start":{"line":21,"column":15},"end":{"line":21,"column":16}},"loc":{"start":{"line":21,"column":29},"end":{"line":23,"column":5}},"line":21}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":91},"end":{"line":8,"column":131}},"type":"cond-expr","locations":[{"start":{"line":8,"column":114},"end":{"line":8,"column":126}},{"start":{"line":8,"column":129},"end":{"line":8,"column":131}}],"line":8},"1":{"loc":{"start":{"line":8,"column":168},"end":{"line":8,"column":382}},"type":"if","locations":[{"start":{"line":8,"column":168},"end":{"line":8,"column":382}},{"start":{"line":8,"column":168},"end":{"line":8,"column":382}}],"line":8},"2":{"loc":{"start":{"line":10,"column":44},"end":{"line":10,"column":195}},"type":"if","locations":[{"start":{"line":10,"column":44},"end":{"line":10,"column":195}},{"start":{"line":10,"column":44},"end":{"line":10,"column":195}}],"line":10}},"s":{"0":1,"1":1,"2":4,"3":4,"4":8,"5":8,"6":8,"7":8,"8":0,"9":8,"10":6,"11":4,"12":10,"13":0,"14":10,"15":10,"16":1,"17":2,"18":4,"19":2,"20":1,"21":2,"22":2,"23":2,"24":1,"25":1},"f":{"0":4,"1":0,"2":6,"3":10,"4":2,"5":4,"6":1,"7":2,"8":2},"b":{"0":[8,0],"1":[8,0],"2":[0,10]},"_coverageSchema":"43e27e138ebf9cfc5966b082cf9a028302ed4184","hash":"40206bea62ed686bdfd6574e8362fa64cfab35e6","contentHash":"955e13bc97eee13608cb24e8f7b8c3619e0079b0bdd2e9d7d201045823d3ce2d"}} -------------------------------------------------------------------------------- /.nyc_output/0b94db04-251f-4ce1-9a43-745d3913961a.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.nyc_output/processinfo/022f543c-edba-469a-8460-52a3a3a0724c.json: -------------------------------------------------------------------------------- 1 | {"uuid":"022f543c-edba-469a-8460-52a3a3a0724c","parent":"0b94db04-251f-4ce1-9a43-745d3913961a","pid":85598,"argv":["/Users/mydspr/.nvm/versions/node/v10.11.0/bin/node","/Users/mydspr/Developer/Repos/use-combined-reducers/node_modules/mocha/bin/_mocha","src/**/**spec.js","--require","@babel/register","--no-config","--no-package","--no-opts","--diff","--extension","js","--reporter","spec","--slow","75","--timeout","2000","--ui","bdd"],"execArgv":[],"cwd":"/Users/mydspr/Developer/Repos/use-combined-reducers","time":1557776710893,"ppid":85591,"root":"e7dbc15f-5dbf-4c76-b744-bcbe574e271f","coverageFilename":"/Users/mydspr/Developer/Repos/use-combined-reducers/.nyc_output/022f543c-edba-469a-8460-52a3a3a0724c.json","files":["/Users/mydspr/Developer/Repos/use-combined-reducers/src/spec.js","/Users/mydspr/Developer/Repos/use-combined-reducers/src/index.js"]} -------------------------------------------------------------------------------- /.nyc_output/processinfo/0b94db04-251f-4ce1-9a43-745d3913961a.json: -------------------------------------------------------------------------------- 1 | {"uuid":"0b94db04-251f-4ce1-9a43-745d3913961a","parent":null,"pid":85591,"argv":["/Users/mydspr/.nvm/versions/node/v10.11.0/bin/node","/Users/mydspr/Developer/Repos/use-combined-reducers/node_modules/.bin/mocha","--require","@babel/register","src/**/**spec.js"],"execArgv":[],"cwd":"/Users/mydspr/Developer/Repos/use-combined-reducers","time":1557776709138,"ppid":85580,"root":"e7dbc15f-5dbf-4c76-b744-bcbe574e271f","coverageFilename":"/Users/mydspr/Developer/Repos/use-combined-reducers/.nyc_output/0b94db04-251f-4ce1-9a43-745d3913961a.json","files":[]} -------------------------------------------------------------------------------- /.nyc_output/processinfo/index.json: -------------------------------------------------------------------------------- 1 | {"processes":{"022f543c-edba-469a-8460-52a3a3a0724c":{"parent":"0b94db04-251f-4ce1-9a43-745d3913961a","children":[]},"0b94db04-251f-4ce1-9a43-745d3913961a":{"parent":null,"children":["022f543c-edba-469a-8460-52a3a3a0724c"]}},"files":{"/Users/mydspr/Developer/Repos/use-combined-reducers/src/spec.js":["022f543c-edba-469a-8460-52a3a3a0724c"],"/Users/mydspr/Developer/Repos/use-combined-reducers/src/index.js":["022f543c-edba-469a-8460-52a3a3a0724c"]},"externalIds":{}} -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "singleQuote": true, 5 | "printWidth": 70, 6 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - stable 5 | 6 | install: 7 | - npm install 8 | 9 | script: 10 | - npm run test 11 | 12 | after_script: 13 | - npm run coverage 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Robin Wieruch 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # useCombinedReducers React Hook 2 | 3 | [![Build Status](https://travis-ci.org/the-road-to-learn-react/use-combined-reducers.svg?branch=master)](https://travis-ci.org/the-road-to-learn-react/use-combined-reducers) [![Slack](https://slack-the-road-to-learn-react.wieruch.com/badge.svg)](https://slack-the-road-to-learn-react.wieruch.com/) [![Greenkeeper badge](https://badges.greenkeeper.io/the-road-to-learn-react/use-combined-reducers.svg)](https://greenkeeper.io/) [![Coverage Status](https://coveralls.io/repos/github/the-road-to-learn-react/use-combined-reducers/badge.svg?branch=master)](https://coveralls.io/github/the-road-to-learn-react/use-combined-reducers?branch=master) ![NPM](https://img.shields.io/npm/l/use-combined-reducers.svg) 4 | 5 | Custom hook to combine all useReducer hooks for one global state container with one dispatch function. Use at top-level and pass dispatch function (and state) down via React's Context API with Provider and Consumer/useContext. 6 | 7 | * [Example Application](https://github.com/the-road-to-learn-react/react-with-redux-philosophy) 8 | * ["How to implement it"-tutorial](https://www.robinwieruch.de/redux-with-react-hooks/). 9 | * Requirements: [reducer](https://www.robinwieruch.de/javascript-reducer/) and [useReducer](https://www.robinwieruch.de/react-usereducer-hook/) explained. 10 | 11 | ## Installation 12 | 13 | `npm install use-combined-reducers` 14 | 15 | Optional TS support: `npm install @types/use-combined-reducers --save-dev` 16 | 17 | ## Usage 18 | 19 | Create a global dispatch function and state object by initializing multiple `useReducer` hooks in `useCombinedReducers`: 20 | 21 | ``` 22 | import React from 'react'; 23 | import useCombinedReducers from 'use-combined-reducers'; 24 | 25 | const App = () => { 26 | const [state, dispatch] = useCombinedReducers({ 27 | myTodos: React.useReducer(todoReducer, initialTodos), 28 | myOtherStuff: React.useReducer(stuffReducer, initialStuff), 29 | }); 30 | 31 | const { myTodos, myOtherStuff } = state; 32 | 33 | ... 34 | } 35 | 36 | export default App; 37 | ``` 38 | 39 | You can pass state and dispatch function down via [props](https://www.robinwieruch.de/react-pass-props-to-component/) or [React's Context API](https://www.robinwieruch.de/react-context-api/). Since passing it down with props is straight forward, the approach with context is demonstrated here. In some file: 40 | 41 | ``` 42 | import React from 'react'; 43 | 44 | export const StateContext = React.createContext(); 45 | export const DispatchContext = React.createContext(); 46 | ``` 47 | 48 | In your top-level React component (or any other component above a component tree which needs managed state): 49 | 50 | ``` 51 | import React from 'react'; 52 | import useCombinedReducers from 'use-combined-reducers'; 53 | 54 | import { StateContext, DispatchContext } from './somefile.js'; 55 | 56 | const App = () => { 57 | const [state, dispatch] = useCombinedReducers({ 58 | myTodos: React.useReducer(todoReducer, initialTodos), 59 | myOtherStuff: React.useReducer(stuffReducer, initialStuff), 60 | }); 61 | 62 | return ( 63 | 64 | 65 | 66 | 67 | 68 | ); 69 | } 70 | 71 | export default App; 72 | ``` 73 | 74 | In some other component which sits below the state/dispatch providing component: 75 | 76 | ``` 77 | import React from 'react'; 78 | 79 | import { StateContext, DispatchContext } from './somefile.js'; 80 | 81 | export default () => { 82 | const state = React.useContext(StateContext); 83 | const dispatch = React.useContext(DispatchContext); 84 | 85 | const { myTodos, myOtherStuff } = state; 86 | 87 | return ( 88 |
89 | ... 90 |
91 | ); 92 | }; 93 | ``` 94 | 95 | ## Contribute 96 | 97 | * `git clone git@github.com:the-road-to-learn-react/use-combined-reducers.git` 98 | * `cd use-combined-reducers` 99 | * `npm install` 100 | * `npm run test` 101 | 102 | ### More 103 | 104 | * [Publishing a Node Package to NPM](https://www.robinwieruch.de/publish-npm-package-node/) 105 | * [Node.js Testing Setup](https://www.robinwieruch.de/node-js-testing-mocha-chai/) 106 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "use-combined-reducers", 3 | "version": "1.0.4", 4 | "description": "", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "build": "webpack --config ./webpack.config.js --mode=production", 8 | "prepare": "npm run build", 9 | "test": "nyc mocha --require @babel/register 'src/**/**spec.js'", 10 | "coverage": "nyc report --reporter=text-lcov | coveralls" 11 | }, 12 | "keywords": [], 13 | "author": "“Robin (https://www.robinwieruch.de)", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "@babel/cli": "^7.4.4", 17 | "@babel/core": "^7.2.2", 18 | "@babel/node": "^7.2.2", 19 | "@babel/plugin-proposal-object-rest-spread": "^7.4.4", 20 | "@babel/preset-env": "^7.2.3", 21 | "@babel/register": "^7.4.4", 22 | "babel-loader": "^8.0.5", 23 | "chai": "^4.2.0", 24 | "coveralls": "^3.0.3", 25 | "mocha": "^6.1.4", 26 | "nyc": "^14.1.1", 27 | "webpack": "^4.31.0", 28 | "webpack-cli": "^3.3.2" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "git+https://github.com/the-road-to-learn-react/use-combined-reducers.git" 33 | }, 34 | "bugs": { 35 | "url": "https://github.com/the-road-to-learn-react/use-combined-reducers/issues" 36 | }, 37 | "homepage": "https://github.com/the-road-to-learn-react/use-combined-reducers#readme", 38 | "dependencies": { 39 | "sinon": "^7.3.2" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const useCombinedReducers = combinedReducers => { 2 | // Global State 3 | const state = Object.keys(combinedReducers).reduce( 4 | (acc, key) => ({ ...acc, [key]: combinedReducers[key][0] }), 5 | {}, 6 | ); 7 | 8 | // Global Dispatch Function 9 | const dispatch = action => 10 | Object.keys(combinedReducers) 11 | .map(key => combinedReducers[key][1]) 12 | .forEach(fn => fn(action)); 13 | 14 | return [state, dispatch]; 15 | }; 16 | 17 | export default useCombinedReducers; 18 | -------------------------------------------------------------------------------- /src/spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { spy } from 'sinon'; 3 | 4 | import useCombinedReducers from './'; 5 | 6 | describe('useCombinedReducer', () => { 7 | it('returns a state object with defined substates', () => { 8 | const [state, dispatch] = useCombinedReducers({ 9 | a: ['1', () => {}], 10 | b: ['2', () => {}], 11 | }); 12 | 13 | expect(state).to.eql({ a: '1', b: '2' }); 14 | }); 15 | 16 | it('returns a dispatch function that calls all child dispatch functions', () => { 17 | const aCallback = spy(); 18 | const bCallback = spy(); 19 | 20 | const [state, dispatch] = useCombinedReducers({ 21 | a: ['1', aCallback], 22 | b: ['2', bCallback], 23 | }); 24 | 25 | dispatch({ type: 'SOME_ACTION' }); 26 | 27 | expect(aCallback.calledOnce).to.eql(true); 28 | expect(bCallback.calledOnce).to.eql(true); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: './src/index.js', 3 | output: { 4 | path: __dirname + '/lib', 5 | filename: 'index.js', 6 | library: 'node-package-open-source-starter', 7 | libraryTarget: 'umd', 8 | }, 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.(js|jsx)$/, 13 | exclude: /node_modules/, 14 | use: ['babel-loader'], 15 | }, 16 | ], 17 | }, 18 | }; 19 | --------------------------------------------------------------------------------