{"id":13450583,"url":"https://github.com/iusehooks/redhooks","last_synced_at":"2026-03-27T04:29:46.743Z","repository":{"id":57349622,"uuid":"165114068","full_name":"iusehooks/redhooks","owner":"iusehooks","description":"Predictable state container for React apps written using Hooks","archived":false,"fork":false,"pushed_at":"2019-02-11T16:21:58.000Z","size":305,"stargazers_count":145,"open_issues_count":2,"forks_count":10,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-12-17T11:11:31.144Z","etag":null,"topics":["hooks","immutability","react-hooks","reacthooks","reducer","redux","state-management","state-tree"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iusehooks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-10T18:54:25.000Z","updated_at":"2024-05-04T06:20:31.000Z","dependencies_parsed_at":"2022-09-15T15:23:09.917Z","dependency_job_id":null,"html_url":"https://github.com/iusehooks/redhooks","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/iusehooks/redhooks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iusehooks%2Fredhooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iusehooks%2Fredhooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iusehooks%2Fredhooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iusehooks%2Fredhooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iusehooks","download_url":"https://codeload.github.com/iusehooks/redhooks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iusehooks%2Fredhooks/sbom","scorecard":{"id":497874,"data":{"date":"2025-08-11","repo":{"name":"github.com/iusehooks/redhooks","commit":"5bdad0e054fe71a3e8617c9ed9c91118d366adb2"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/22 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"70 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-6chw-6frg-f759","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-w8qv-6jwh-64r5","Warn: Project is vulnerable to: GHSA-c6rq-rjc2-86v2","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-3gx7-xhv7-5mx3","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3","Warn: Project is vulnerable to: MAL-2023-462","Warn: Project is vulnerable to: GHSA-q42p-pg8m-cqh6","Warn: Project is vulnerable to: GHSA-w457-6q6x-cgp9","Warn: Project is vulnerable to: GHSA-62gr-4qp9-h98f","Warn: Project is vulnerable to: GHSA-f52g-6jhx-586p","Warn: Project is vulnerable to: GHSA-2cf5-4w76-r9qv","Warn: Project is vulnerable to: GHSA-3cqr-58rm-57f8","Warn: Project is vulnerable to: GHSA-g9r4-xpmj-mj65","Warn: Project is vulnerable to: GHSA-q2c6-c6pm-g3gh","Warn: Project is vulnerable to: GHSA-765h-qjxv-5f44","Warn: Project is vulnerable to: GHSA-f2jv-r9rf-7988","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546","Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-4xcv-9jjx-gfj3","Warn: Project is vulnerable to: GHSA-7wpw-2hjm-89gp","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-fhjf-83wg-r2j9","Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-4g88-fppr-53pp","Warn: Project is vulnerable to: GHSA-4jqc-8m5r-9rpr","Warn: Project is vulnerable to: GHSA-j44m-qm6p-hp7m","Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9","Warn: Project is vulnerable to: GHSA-r628-mhmh-qjhw","Warn: Project is vulnerable to: GHSA-9r2w-394v-53qc","Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh","Warn: Project is vulnerable to: GHSA-qq89-hq3f-393p","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T20:57:55.416Z","repository_id":57349622,"created_at":"2025-08-19T20:57:55.416Z","updated_at":"2025-08-19T20:57:55.416Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31019155,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-27T03:51:26.850Z","status":"ssl_error","status_checked_at":"2026-03-27T03:51:09.693Z","response_time":164,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hooks","immutability","react-hooks","reacthooks","reducer","redux","state-management","state-tree"],"created_at":"2024-07-31T07:00:36.377Z","updated_at":"2026-03-27T04:29:46.704Z","avatar_url":"https://github.com/iusehooks.png","language":"JavaScript","funding_links":[],"categories":["Packages","JavaScript"],"sub_categories":[],"readme":"# \u003cimg src='https://raw.githubusercontent.com/iusehooks/redhooks/master/logo/logo.png' width=\"224\" height='61' alt='Redhooks Logo' /\u003e\n\nRedhooks is a tiny React utility library for holding a predictable state container in your React apps. \nInspired by [Redux](https://redux.js.org), it reimplements the redux paradigm of state-management by using React's new Hooks and Context API, which have been [officially released](https://reactjs.org/docs/hooks-reference.html) by the React team.\n- [Motivation](#motivation)\n- [Basic Example](#basic-example)\n- [Apply Middleware](#apply-middleware)\n- [Usage with React Router](#usage-with-react-router)\n- [Isolating Redhooks Sub-Apps](#isolating-redhooks-sub-apps)\n- [Redhooks API Reference](#redhooks-api-reference)\n- [CodeSandbox Examples](#codesandbox-examples)\n- [License](#license)\n\n[![Build Status](https://travis-ci.org/iusehooks/redhooks.svg?branch=master)](https://travis-ci.org/iusehooks/redhooks) [![Package size](https://img.shields.io/bundlephobia/minzip/redhooks.svg)](https://bundlephobia.com/result?p=redhooks) [![Coverage Status](https://coveralls.io/repos/github/iusehooks/redhooks/badge.svg?branch=master)](https://coveralls.io/github/iusehooks/redhooks?branch=master) ![License](https://img.shields.io/npm/l/redhooks.svg?style=flat) [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Predictable%20state%20container%20for%20React%20apps%20written%20using%20Hooks\u0026url=https://github.com/iusehooks/redhooks\u0026hashtags=reactjs,webdev,javascript)\n\n# Installation\n```sh\nnpm install --save redhooks\n```\n\n# Motivation\n\nIn the [Reactjs docs](https://reactjs.org/docs/hooks-custom.html) a nice paragraph titled _useYourImagination()_ suggests to think of different possible usages of functionality Hooks provide, which is essentially what Redhooks tries to do.\nThis package does not use any third party library, being only dependent upon the Hooks and the Context API.\nYou do not need to install `react-redux` to connect your components to the store because you can have access to it directly from any of your function components by utilizing the `useStore` Redhooks API.\nHooks are [not allowed within class Components](https://reactjs.org/docs/hooks-rules.html), for using the store within them Redhooks exposes a Higher Order Component (HOC) named `connect`.\nIt also supports the use of middleware like `redux-thunk` or `redux-saga` or your own custom middleware conforming to the middleware's API.\n\n# Basic Example\n\nRedhooks follows the exact same principles of redux, which was the package's inspiration.\n* the total state of your app is stored in an object tree inside of a single store object.\n* state is _read only_, so the only way to change the state is to dispatch an [action](https://redux.js.org/basics/actions), an object describing the changes to be made to the state.\n* to specify how the actions transform the state tree, you write pure reducers.\n\n## Store\n\n`store.js`\n```js\nimport { createStore, combineReducers } from \"redhooks\";\n\n// function reducer\nconst hello = (\n  state = { phrase: \"good morning\" },\n  { type, payload }\n) =\u003e {\n  switch (type) {\n    case \"SAY_HELLO\":\n      return { ...state, phrase: payload };\n    default:\n      return state;\n  }\n};\n\n// function reducer\nconst counter = (state = 0, { type, payload }) =\u003e {\n  switch (type) {\n    case \"INCREMENT\":\n      return state + 1;\n    case \"DECREMENT\":\n      return state - 1;\n    default:\n      return state;\n  }\n};\n\n// You can use the combineReducers function\nconst rootReducer = combineReducers({ hello, counter });\nconst store = createStore(rootReducer);\n\n// or if you want to be less verbose you can pass a plain object whose values are reducer functions\nconst store = createStore({ hello, counter });\n\n// eventually we can pass to createStore as second arg an opts object like:\n// const opts = { preloadedState: { counter: 10 }, initialAction: { type: \"INCREMENT\" } }\n// const store = createStore(rootReducer, opts);\n\nexport default store;\n```\n\n`App.js`\n```js\nimport Provider from \"redhooks\";\nimport store from \"./store\";\n\nfunction App() {\n  return (\n      \u003cProvider store={store}\u003e\n        \u003cDispatchAction /\u003e\n        \u003cDispatchActionExpensive /\u003e\n        \u003cReadFromStore /\u003e\n      \u003c/Provider\u003e\n  );\n}\n\nconst rootElement = document.getElementById(\"root\");\nReactDOM.render(\u003cApp /\u003e, rootElement);\n```\n\n## Dispatching Sync and Async Actions - Non-expensive rendering operation\nIf your component does not require expensive rendering, you can use the `useStore` Redhooks API within your\nfunctional component in order to access the Redhooks store. Class or function components that perform expensive rendering operations can be connected to the store by using the `connect` Redhooks HOC which takes care to avoid unnecessary re-rendering in order to improve performance. We'll be able to see this in action below:\n\n`./components/DispatchAction.js`\n```js\nimport React from \"react\";\nimport { useStore } from \"redhooks\";\n\nconst DispatchAction = () =\u003e {\n  const { dispatch } = useStore();\n  return (\n     \u003cdiv\u003e\n        \u003cbutton\n          onClick={() =\u003e\n            dispatch({\n              type: \"SAY_HELLO\",\n              payload: \"hello\"\n            })\n          }\n        \u003e\n          Say Hello\n        \u003c/button\u003e\n        \u003cbutton onClick={() =\u003e dispatch({ type: \"INCREMENT\" })}\u003e\n          Sync Increment Counter\n        \u003c/button\u003e\n        \u003cbutton\n          onClick={() =\u003e\n            setTimeout(() =\u003e dispatch({ type: \"DECREMENT\" }), 3000)\n          }\n        \u003e\n          Async Decrement Counter\n        \u003c/button\u003e\n      \u003c/div\u003e\n  );\n};\n\nexport default DispatchAction;\n```\n\n## Dispatching Sync and Async Actions - Expensive rendering operation\nFor components requiring expensive rendering, the use of `connect` helps to avoid any unnecessary re-rendering.\n\n`./components/DispatchActionExpensive.js`\n```js\nimport React from \"react\";\nimport { connect } from \"redhooks\";\n\nconst DispatchActionExpensive = props =\u003e (\n     \u003cdiv\u003e\n        \u003cbutton onClick={() =\u003e props.dispatch({ type: \"INCREMENT\" })}\u003e\n          Sync Increment Counter\n        \u003c/button\u003e\n        \u003cbutton\n          onClick={() =\u003e\n            setTimeout(() =\u003e props.dispatch({ type: \"DECREMENT\" }), 3000)\n          }\n        \u003e\n          Async Decrement Counter\n        \u003c/button\u003e\n      \u003c/div\u003e\n);\n\nexport default connect()(DispatchActionExpensive);\n```\n\n## Use Store from a Function Component\n\n`./components/ReadFromStore.js`\n```js\nimport React from \"react\";\nimport { useStore } from \"redhooks\";\n\nconst ReadFromStore = () =\u003e {\n  const { state } = useStore();\n  const { hello, counter } = state;\n  return (\n    \u003csection\u003e\n      \u003ch1\u003e{hello.phrase}\u003c/h1\u003e\n      \u003cspan\u003e{counter}\u003c/span\u003e\n    \u003c/section\u003e\n  );\n};\n\nexport default ReadFromStore;\n```\n\n\u003e **Tip**: If your function component requires an expensive render, you should use the `connect` HOC Redhooks API.\n\n## Use Store from a Class Component\n\n```js\nimport React, { Component } from \"react\";\nimport { connect } from \"redhooks\";\n\nclass ReadFromStore extends Component {\n  render() {\n    const { hello, counter } = this.props;\n    return (\n        \u003csection\u003e\n            \u003ch1\u003e{hello.phrase}\u003c/h1\u003e\n            \u003cspan\u003e{counter}\u003c/span\u003e\n        \u003c/section\u003e\n    );\n  }\n};\n\nfunction mapStateToProp(state, ownProps) {\n  return {\n    hello: state.hello,\n    counter: state.counter\n  };\n}\n\nexport default connect(mapStateToProp)(ReadFromStore);\n```\n\n# Apply Middleware\n\nAs for Redux, [middleware](https://redux.js.org/advanced/middleware) is a way to extend Redhooks with custom functionality.\nMiddleware are functions which receive the store's `dispatch` and `getState` as named arguments, and subsequently return a function. Redhooks supports the use of redux middleware like [redux-thunk](https://www.npmjs.com/package/redux-thunk), [redux-saga](https://www.npmjs.com/package/redux-saga) or you could write custom middleware to conform to the middleware API. \n\n## Custom middleware - Logger Example\n\n```js\nconst logger = store =\u003e next =\u003e action =\u003e {\n  console.log('dispatching', action)\n  let result = next(action)\n  console.log('next state', store.getState())\n  return result\n}\n```\n\n##  Use `redux-thunk` and `redux-saga`\n\n```js\nimport React from \"react\";\nimport { render } from \"react-dom\";\nimport Provider, { createStore } from \"redhooks\";\nimport thunk from \"redux-thunk\";\nimport createSagaMiddleware from \"redux-saga\";\nimport reducer from \"./reducers\";\n\nconst sagaMiddleware = createSagaMiddleware();\n\nconst middlewares = [thunk, sagaMiddleware];\n\nconst store = createStore(reducer, { middlewares });\n\nfunction* helloSaga() {\n  console.log(\"Hello Sagas!\");\n}\n// redux-saga needs to run as soon the store is ready\nstore.onload = () =\u003e sagaMiddleware.run(helloSaga);\n\nrender(\n    \u003cProvider store={store}\u003e\n        \u003cDispatchAction /\u003e\n        \u003cReadFromStore /\u003e\n    \u003c/Provider\u003e,\n  document.getElementById(\"root\")\n);\n```\n\n# Usage with React Router\nApp routing can be handled using [React Router](https://github.com/ReactTraining/react-router).\n\n```js\nimport React from 'react'\nimport Provider from 'redhooks'\nimport { BrowserRouter as Router, Route, Switch } from 'react-router-dom'\nimport Home from './Home'\nimport About from './About'\n\nconst App = ({ store }) =\u003e (\n  \u003cProvider store={store}\u003e\n    \u003cRouter\u003e\n      \u003cSwitch\u003e\n        \u003cRoute exact path=\"/\" component={Home} /\u003e\n        \u003cRoute exact path=\"/about\" component={About} /\u003e\n      \u003c/Switch\u003e\n    \u003c/Router\u003e\n  \u003c/Provider\u003e\n)\n\nexport default App\n```\n\n```js\nimport React from 'react'\nimport { render } from 'react-dom'\nimport { createStore } from 'redhooks'\nimport thunk from \"redux-thunk\";\nimport rootReducer from \"./reducers\"\nimport App from './App'\n\nconst opts = {\n  preloadedState: { counter: 9 },\n  initialAction: { type: \"INCREMENT\" },\n  middlewares: [thunk]\n};\n\nconst store = createStore(rootReducer, opts)\n\nrender(\u003cApp store={store} /\u003e, document.getElementById('app'))\n```\n\n# Isolating Redhooks Sub-Apps\n\n```js\nimport React from \"react\";\nimport Provider, { createStore } from \"redhooks\";\nimport ReadFromStore from \"./components/ReadFromStore\";\nimport Footer from \"./components/Footer\";\n\nconst counter = (state = 0, { type, payload }) =\u003e {\n  switch (type) {\n    case \"INCREMENT\":\n      return state + 1;\n    case \"DECREMENT\":\n      return state - 1;\n    default:\n      return state;\n  }\n};\n\nconst store = createStore(counter);\n\nexport default function SubApp() {\n  return (\n    \u003cProvider store={store}\u003e\n      \u003cDispatchAction /\u003e\n      \u003cReadFromStore /\u003e\n    \u003c/Provider\u003e\n  );\n}\n```\n\nEach instance will be independent and it will have its own store.\n\n```js\nimport React from \"react\";\nimport SubApp from \"./SubApp\";\n\nfunction App() {\n  return (\n    \u003cReact.Fragment\u003e\n      \u003cSubApp /\u003e\n      \u003cSubApp /\u003e\n    \u003c/React.Fragment\u003e\n  );\n}\n\nconst rootElement = document.getElementById(\"root\");\nReactDOM.render(\u003cApp /\u003e, rootElement);\n```\n\n# Redhooks API Reference\n\n* [createStore](#createStore)\n* [combineReducers](#combineReducers)\n* [connect](#connect)\n* [bindActionCreators](#bindActionCreators)\n* [Provider](#Provider)\n* [useStore](#useStore)\n\n## createStore\n```js\ncreateStore(reducer, [opts])\n```\n`createStore` returns the store object to be passed to the `\u003cProvider store={store} /\u003e`.\n* The `reducer` argument might be a single reducer function, a function returned by `combineReducers` or a plain object whose values are reducer functions (if your store requires multiple reducers).\n* The `opts` optional argument is an object which allows you to pass a `preloadedState`, `initialAction` and `middlewares`.\n\u003e The store is ready when the `Provider` is mounted, after which an `onload` event will be triggered.\n\n#### Example\n```js\nconst opts = {\n    preloadedState: 1,\n    initialAction: { type: \"DECREMENT\" },\n    middlewares: [thunk, sagaMiddleware, logger]\n};\nconst store = createStore(reducer, opts);\nstore.onload = ({ dispatch }) =\u003e dispatch({ type: \"INCREMENT\" });\n```\n\n## combineReducers\n```js\ncombineReducers(reducers)\n```\n`combineReducers` combines an object whose props are different reducer functions, into a single reducer function\n* The `reducers` argument is an object whose values correspond to different reducing functions that need to be combined into one.\n\n#### Example\n```js\nconst rootReducer = combineReducers({ counter, otherReducer })\nconst store = createStore(rootReducer)\n```\n\n## connect\n```js\nconnect([mapStateToProps], [mapDispatchToProps])\n```\n`connect` function connects a React component to a Redhooks store. It returns a connected component class that wraps the component you passed in taking care to avoid unnecessary re-rendering. It should be used if your class or function components require expensive rendering.\n\n* If a `mapStateToProps` function is passed, your component will be subscribed to Redhooks store. Any time the store is updated, `mapStateToProps` will be called. The results of `mapStateToProps` must be a plain object, which will be merged into your component’s props. If you don't want to connect to Redhooks store, pass null or undefined in place of mapStateToProps.\n* `mapDispatchToProps`, if passed, may be either a function that returns a plain object whose values, themselves, are functions or a plain object whose values are [action creator](#action-creator) functions. In both cases the props of the returned object will be merged in your component’s props. If is not passed your component will receive `dispatch` prop by default.\n\n#### Example\n```js\nconst mapStateToProps = (state, ownProps) =\u003e ({ counter: state.counter })\nconst mapDispatchToProps = dispatch =\u003e ({ increment: action =\u003e dispatch({ type: action })})\n// or\nconst mapDispatchToProps = { increment: type =\u003e ({ type })}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(ReactComponent)\n```\n\n## bindActionCreators\n```js\nbindActionCreators(actionCreators, dispatch)\n```\n\n`bindActionCreators` turns an object whose values are [action creators](#action-creator) into an object with the\nsame keys, but with every function wrapped in a `dispatch` call so they\nmay be invoked directly.\n \n* `actionCreators` An object whose values are action creator functions or plain objects whose values are action creator functions\n* `dispatch` The dispatch function available on your Redhooks store.\n\n#### Action creator\nAn action creator is a function that creates an action.\n\n```js\ntype ActionCreator = (...args: any) =\u003e Action | AsyncAction\n```\n\n#### Example\n`actions.js`\n\n```js\nexport const action_1 = action_1 =\u003e action_1\nexport const action_2 = action_2 =\u003e action_2\nexport const action_3 = action_3 =\u003e action_3\n```\n\n`YourComponentConnected.js`\n```js\nimport React from \"react\";\nimport { connect, bindActionCreators } from \"redhooks\";\nimport * as actions from \"./actions\";\n\nconst YourComponent = ({ actions, counter }) =\u003e (\n  \u003cdiv\u003e\n    \u003ch1\u003ecounter\u003c/h1\u003e\n    \u003cbutton onClick={actions.action_1}\u003eaction_1\u003c/button\u003e\n    \u003cbutton onClick={actions.action_2}\u003eaction_2\u003c/button\u003e\n    \u003cbutton onClick={actions.action_2}\u003eaction_3\u003c/button\u003e\n  \u003c/div\u003e\n);\n\nconst mapStateToProps = state =\u003e ({\n  counter: state.counter\n});\n\n// a verbose way\nconst mapDispatchToProps = dispatch =\u003e ({\n  actions: bindActionCreators(actions, dispatch)\n});\nexport default connect(\n  mapStateToProps,\n  mapDispatchToProps\n)(YourComponent);\n\n// or simply\nexport default connect(\n  mapStateToProps,\n  { actions }\n)(YourComponent);\n```\n\n## Provider\nThe `\u003cProvider /\u003e` makes the Redhooks store available to any nested components.\n\n#### Example\n```js\nimport React from \"react\";\nimport Provider from \"redhooks\";\nimport store from \"./store\";\nimport ReadFromStore from \"./components/ReadFromStore\";\nimport Footer from \"./components/Footer\";\n\nexport default function App() {\n  return (\n    \u003cProvider store={store}\u003e\n      \u003cDispatchAction /\u003e\n      \u003cReadFromStore /\u003e\n    \u003c/Provider\u003e\n  );\n}\n```\n\n## useStore\n```js\nuseStore()\n```\n`useStore` can be only used within a function component and it returns the `store`.\n* The `store` is an object whose props are the `state` and the `dispatch`.\n\n#### Example\n```js\nimport React from \"react\";\nimport { useStore } from \"redhooks\";\n\nconst Example = () =\u003e {\n  const { state, dispatch } = useStore(); // do not use it within a Class Component\n  const { counter } = state;\n  return (\n    \u003csection\u003e\n      \u003cspan\u003e{counter}\u003c/span\u003e\n      \u003cbutton onClick={() =\u003e dispatch({ type: \"INCREMENT\" })}\u003e\n        Increment Counter\n      \u003c/button\u003e\n    \u003c/section\u003e\n  );\n};\n\nexport default Example;\n```\n\n# CodeSandbox Examples\n\nFollowing few open source projects implemented with `redux` have been migrated to `redhooks`:\n\n* Shopping Cart: [Sandbox](https://codesandbox.io/s/5yn1258y4l)\n* TodoMVC: [Sandbox](https://codesandbox.io/s/7jyq991p90)\n* Tree-View: [Sandbox](https://codesandbox.io/s/rmw98onnlp)\n* Saga-Middleware: [Sandbox](https://codesandbox.io/s/48pomo7rx7)\n* Redux-Thunk: [Sandbox](https://codesandbox.io/s/n02r5400mp)\n\n# License\n\nThis software is free to use under the MIT license.\nSee the [LICENSE file](/LICENSE.md) for license text and copyright information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiusehooks%2Fredhooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiusehooks%2Fredhooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiusehooks%2Fredhooks/lists"}