{"id":23473299,"url":"https://github.com/abhay-khandwekar/react-hooka","last_synced_at":"2026-04-25T23:38:09.960Z","repository":{"id":143905457,"uuid":"305364377","full_name":"abhay-khandwekar/react-hooka","owner":"abhay-khandwekar","description":"\"react-hooka\" is React-hook based state management library. \"react-hooka\" supports both synchronous and queued-asynchronous (FIFO) actions. All asynchronous state update operations are guaranteed to change the application state in the order of asynchronous-operation invocation.","archived":false,"fork":false,"pushed_at":"2020-10-28T07:36:53.000Z","size":31,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-06T00:24:56.583Z","etag":null,"topics":["async-await","asynchronous","asynchronous-actions","asynchronous-store","hook","hooks","javascript-promise","promise","react","react-components","react-hook-store","react-hooks","slice-state","state-management","store","store-slice","synchronous-store"],"latest_commit_sha":null,"homepage":"","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/abhay-khandwekar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-10-19T11:41:07.000Z","updated_at":"2020-10-28T07:35:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"fd11201a-2800-49a2-80f3-38236ea620c2","html_url":"https://github.com/abhay-khandwekar/react-hooka","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/abhay-khandwekar/react-hooka","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abhay-khandwekar%2Freact-hooka","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abhay-khandwekar%2Freact-hooka/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abhay-khandwekar%2Freact-hooka/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abhay-khandwekar%2Freact-hooka/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abhay-khandwekar","download_url":"https://codeload.github.com/abhay-khandwekar/react-hooka/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abhay-khandwekar%2Freact-hooka/sbom","scorecard":{"id":160656,"data":{"date":"2025-08-11","repo":{"name":"github.com/abhay-khandwekar/react-hooka","commit":"3e10046ac5972b79d36175fd547c2649febca2bd"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"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":"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":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Code-Review","score":0,"reason":"Found 0/10 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":"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":"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":"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:0","Info: FSF or OSI recognized license: MIT License: LICENSE: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 'main'"],"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":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"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-16T13:19:24.299Z","repository_id":143905457,"created_at":"2025-08-16T13:19:24.299Z","updated_at":"2025-08-16T13:19:24.299Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32280981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T18:29:39.964Z","status":"ssl_error","status_checked_at":"2026-04-25T18:29:32.149Z","response_time":59,"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":["async-await","asynchronous","asynchronous-actions","asynchronous-store","hook","hooks","javascript-promise","promise","react","react-components","react-hook-store","react-hooks","slice-state","state-management","store","store-slice","synchronous-store"],"created_at":"2024-12-24T17:18:56.413Z","updated_at":"2026-04-25T23:38:09.954Z","avatar_url":"https://github.com/abhay-khandwekar.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"react-hooka  \n================\n----------------------------------------------------------------------\nGlobal state management based on React-hooks, with built-in support for both synchronous \u0026 queued-asynchronus (FIFO) actions.\n\n----------------------------------------------------------------------\nTable of Contents\n-----------------\n* [Introduction](#introduction) \n* [Install](#install)\n* [Features, Instructions and Glossary](#features-instructions-and-glossary)\n    * [Store](#store)   \n    * [Slice](#slice)\n    * [Actions](#actions)\n    * [Synchronous Actions](#synchronous-actions)\n    * [Asynchronous Actions](#asynchronous-actions)\n* [Using react-hooka](#using-react-hooka) \n* [Example](#example)\n* [Live Examples](#live-examples)\n\n### Introduction:\n\"react-hooka\" is React-hook based state management library. \"react-hooka\" supports both synchronous \u0026 queued-asynchronous (FIFO) actions. \n\nAll asynchronous state update operations are guaranteed to change the application state in the order of asynchronous-operation invocation.\n\nThe \"react-hooka\" is designed to have multiple independent slices within the global store. Each slice is an independent sandbox which contain \"state\" as well as \"actions\". Operations performed in context of a given \"slice\" does not affect other \"slices\" within the store.\n\nReact-components which subscribes to a given \"slice\" are only re-rendered when the subscribed slice-state gets any update. React-components using a slice have option to optout re-renders on slice-state updates if the need be.\n\n### Install: \n```sh\nnpm install react-hooka\n```\n\n## Features, Instructions and Glossary:\n\n### Store:\nStore refers to a global object holding application state and available action on the state in a React application. \n\nUnder the hood, store maintains multiple slices, and each of the slice independently manages its state using the actions available on its state.\n\n### Slice:\nSlice is an independent subset of the store. A slice holds a subset of application state and defined actions on its state.\n\nAny operation in context of a given slice does not impact other slices within the store. Only the components using (subscribed to) a given slice are notified of the state updates and may perform rerender if required.\n\n### Actions:\nActions are methods responsible to update the state of a slice. Each action is identified by an \"Action-Identifier\" which must be unique string value within the slice.\n\nActions methods receives \"currentState\" as parameter which represents the current snapshot of slice-state.\n\nActions must return \"updatedState\". The state returned by the Action is replaced into the slice-state by the \"react-hooka\".\n\n**Note - v2.0.0: State returned by the Action is replaced, not merged into the existing state.**\n\nActions are of two kinds:\n1. [Synchronous Actions](#synchronous-actions)\n2. [Asynchronous Actions](#asynchronous-actions)\n\n### Synchronous Actions:\nSynchronous action performs state update in synchronous fashion and are blocking in nature. All state update operations which do not perform I/O or Network operations are cadidates of synchronous actions. \n\n```jsx\n// Synchronous Action named \"SYNCHRONUS_ACTION_IDENTIFIER\"\n{\nSYNCHRONUS_ACTION_IDENTIFIER: (currentState) =\u003e {\n      try {\n        const updatedState = {...currentState, n1: 100 };\n        return updatedState;\n      } catch (error) {\n        throw new Error(error.message);\n      }\n    }\n}\n```\n### Asynchronous Actions:\nAsynchronous action performs state update in asynchronous fashion and are non-blocking in nature. All Asynchronous operations are expected to return a \"promise\". All state update operations which perform I/O or Network oprations are cadidates of asynchronous actions. \n\n```jsx\n// Asynchronous Action named \"ASYNCHRONUS_ACTION_IDENTIFIER\"\n{\n    ASYNCHRONUS_ACTION_IDENTIFIER: (currentState) =\u003e {\n      return new Promise((resolve, reject) =\u003e {\n        (async () =\u003e {\n          try {\n            setTimeout(() =\u003e {\n              const updatedState = {...currentState, n1: 100 };\n              resolve(updatedState);\n            }, 100);\n          } catch (error) {\n            reject(new Error(error.message));\n          }\n        })();\n      });\n    }\n}\n```\n### Using react-hooka:\nUsing react-hooka is straight forward, which requires following steps:\n\n***Initialise store-slice (state and actions belonging to a slice) using \"initStoreSlice\" method.***\n\n\"initStoreSlice\" method takes 3 parameters:\n\n1. **sliceIdentifier:** Apllication wide unique string value to identify store-slice.\n2. **actions:** An object holding all the \"actions\" to be performed on the slice-state. All actions within the \"actions\" object need to have string \"Action-Identifier\" which should be unique within the slice.\n3. **initialState:** An object having initial state of the slice. \n```jsx\nimport { initStoreSlice } from \"react-hooka\";\n\n  const actions = {\n  SYNCHRONUS_ACTION_IDENTIFIER: (currentState) =\u003e {\n    try {\n      const updatedState = {...currentState, n1: 100 };\n      return updatedState;\n    } catch (error) {\n      throw new Error(error.message);\n    }\n  },\n  ASYNCHRONUS_ACTION_IDENTIFIER: (currentState) =\u003e {\n    return new Promise((resolve, reject) =\u003e {\n      (async () =\u003e {\n        try {\n          setTimeout(() =\u003e {\n            const updatedState = {...currentState, n2: 200 };\n            resolve(updatedState);\n          }, 100);\n        } catch (error) {\n          reject(new Error(error.message));\n        }\n      })();\n    });\n  }\n};\n\nconst initialState = {\n    n1: 10,\n    n2: 20,\n    n3: 30\n  };\n\ninitStoreSlice(\"TEST_STORE\", actions, initialState);\n```\n***Use \"react-hooka\" in React component for state management.***\n1. Import **useStore** hook from \"react-hooka\".\n```jsx\nimport { useStore } from \"react-hooka\";\n```\n2. Use the **useStore** hook with the slice-name of the slice in context.\n```jsx\nconst {state, dispatch, dispatchAsync} = useStore(\"TEST_STORE\");\n```\n**state** represents the current state of the slice-state.\n\n**dispatch** method can be used to perform **synchronous (blocking)** operation on slice-state.\n\n**dispatchAsync** method can be used to perform **asynchronous (non-blocking)** operation on slice-state.\n\n***OPTIONAL OPTOUT from rerendering of React-components on slice-state updates.***\n\nThere might be cases when React-components are only performing actions but not displaying the state (*such as a FORM only adding new items to state but not displaying existing items.*). In such cases React-components can optout rerenders by passing \"false\" to the 2nd parameter **shouldTriggerRerender** of **useStore** hook. \n\nBy default, value of **shouldTriggerRerender** is **true**, thus all slice-state updates will trigger rerender on React-components which are using **useStore** hook.\n\n```jsx\nconst { state, dispatch, dispatchAsync } = useStore(\"TEST_STORE\", false);\n\nOR\n\n// Not using \"state\" at all.\nconst { dispatch, dispatchAsync } = useStore(\"TEST_STORE\", false);\n```\n\n***Delete a store-slice if needed.***\n\nIf a store-slice is no more needed, it can be deleted from the global-store. **deleteStoreSlice** method of \"react-hooka\" can be used to delete a store-slice.\n\n```jsx\nimport { deleteStoreSlice } from \"react-hooka\";\n\ndeleteStoreSlice(\"SLICE_NAME\");\n```\n### Example:\n\n**1. Configure store slice:**\n\n```jsx\n// FILE: testStore.js\n\nimport { initStoreSlice } from \"react-hooka\";\n\nconst init = () =\u003e {\n  const actions = {\n    UPDATE1: (currentState) =\u003e {\n      try {\n        const updatedState = {...currentState, n1: 100 };\n        return updatedState;\n      } catch (error) {\n        throw new Error(error.message);\n      }\n    },\n\n    UPDATE2: (currentState) =\u003e {\n      try {\n        const updatedState = {...currentState, n2: 200 };\n        return updatedState;\n      } catch (error) {\n        throw new Error(error.message);\n      }\n    },\n\n    UPDATE3: (currentState) =\u003e {\n      try {\n        const updatedState = {...currentState, n3: 300 };\n        return updatedState;\n      } catch (error) {\n        throw new Error(error.message);\n      }\n    },\n\n    UPDATE1_ASYNC: (currentState) =\u003e {\n      return new Promise((resolve, reject) =\u003e {\n        (async () =\u003e {\n          try {\n            setTimeout(() =\u003e {\n              const updatedState = {...currentState, n1: 1000 };\n              resolve(updatedState);\n            }, 100);\n          } catch (error) {\n            reject(new Error(error.message));\n          }\n        })();\n      });\n    },\n\n    UPDATE2_ASYNC: (currentState) =\u003e {\n      return new Promise((resolve, reject) =\u003e {\n        (async () =\u003e {\n          try {\n            setTimeout(() =\u003e {\n              const updatedState = {...currentState, n2: 2000 };\n              resolve(updatedState);\n            }, 500);\n          } catch (error) {\n            reject(new Error(error.message));\n          }\n        })();\n      });\n    },\n\n    UPDATE3_ASYNC: (currentState) =\u003e {\n      return new Promise((resolve, reject) =\u003e {\n        (async () =\u003e {\n          try {\n            setTimeout(() =\u003e {\n              const updatedState = {...currentState, n3: 3000 };\n              resolve(updatedState);\n            }, 800);\n          } catch (error) {\n            reject(new Error(error.message));\n          }\n        })();\n      });\n    }\n  };\n\n  const initialState = {\n    n1: 10,\n    n2: 20,\n    n3: 30\n  };\n\n  initStoreSlice(\"TEST_STORE\", actions, initialState);\n};\n\nexport default init;\n```\n\n**2. Initialize store slice:**\n\n```jsx\n// FILE: index.js\n\nimport React from \"react\";\nimport ReactDOM from \"react-dom\";\n\nimport App from \"./App\";\nimport initTestStore from \"./store/testStore\";\n\n// Initialising \"TEST_STORE\"\ninitTestStore();\n\nconst rootElement = document.getElementById(\"root\");\nReactDOM.render(\n  \u003cReact.StrictMode\u003e\n    \u003cApp /\u003e\n  \u003c/React.StrictMode\u003e,\n  rootElement\n);\n```\n\n**3. Managing state in component:**\n\n```jsx\n// FILE: App.js\n\nimport React from \"react\";\nimport { useStore } from \"react-hooka\";\nimport \"./styles.css\";\n\nexport default function App() {\n  const { state, dispatch, dispatchAsync } = useStore(\"TEST_STORE\");\n  \n  const SyncUpdate = () =\u003e {\n    dispatch(\"UPDATE1\");\n    dispatch(\"UPDATE2\");\n    dispatch(\"UPDATE3\");\n  };\n\n  const AsyncUpdate = () =\u003e {\n    dispatchAsync(\"UPDATE1_ASYNC\");\n    dispatchAsync(\"UPDATE2_ASYNC\");\n    dispatchAsync(\"UPDATE3_ASYNC\");\n  };\n\n  return (\n    \u003cdiv className=\"App\"\u003e\n      \u003cp\u003e1. {state.n1}\u003c/p\u003e\n      \u003cp\u003e2. {state.n2}\u003c/p\u003e\n      \u003cp\u003e3. {state.n3}\u003c/p\u003e\n      \u003cp\u003e\u003cbutton onClick={SyncUpdate}\u003eSynchronous Update\u003c/button\u003e\u003c/p\u003e\n      \u003cp\u003e\u003cbutton onClick={AsyncUpdate}\u003eAsynchronous Update\u003c/button\u003e\u003c/p\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Live Examples:\n\n1. **State update with Synchronous and Asynchronous actions -**\n[https://codesandbox.io/s/global-statehook-sync-async-actions-rkipy](https://codesandbox.io/s/global-statehook-sync-async-actions-rkipy)\n2. **Optout component rerender on state update -**\n[https://codesandbox.io/s/global-statehook-optout-rerender-zuvo6](https://codesandbox.io/s/global-statehook-optout-rerender-zuvo6)\n3. **Using multiple state-slices on one component -**\n[https://codesandbox.io/s/global-statehook-multiple-state-slices-9nec4?file=/src/index.js](https://codesandbox.io/s/global-statehook-multiple-state-slices-9nec4?file=/src/index.js)\n4. **Using multiple state-slices through multiple components -**\n[https://codesandbox.io/s/global-statehook-multiple-state-slices-multiple-components-x7e98?file=/src/App.js](https://codesandbox.io/s/global-statehook-multiple-state-slices-multiple-components-x7e98?file=/src/App.js)\n\n### Author:\nAbhay Kumar\n\n### License:\nThis project is licensed under the MIT License.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabhay-khandwekar%2Freact-hooka","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabhay-khandwekar%2Freact-hooka","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabhay-khandwekar%2Freact-hooka/lists"}