{"id":13790062,"url":"https://github.com/tnfe/clean-state","last_synced_at":"2026-03-08T21:41:28.831Z","repository":{"id":53611989,"uuid":"327308474","full_name":"tnfe/clean-state","owner":"tnfe","description":"🐻 A pure and compact state manager, using React-hooks native implementation, automatically connect the module organization architecture. 🍋","archived":false,"fork":false,"pushed_at":"2021-03-30T03:23:08.000Z","size":132,"stargazers_count":112,"open_issues_count":2,"forks_count":16,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-10-21T15:33:34.328Z","etag":null,"topics":["flux","hooks","mobx","react","react-hooks-module","reducer","redux","state"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/tnfe.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}},"created_at":"2021-01-06T12:43:04.000Z","updated_at":"2025-06-08T18:17:32.000Z","dependencies_parsed_at":"2022-09-16T14:50:59.508Z","dependency_job_id":null,"html_url":"https://github.com/tnfe/clean-state","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tnfe/clean-state","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tnfe%2Fclean-state","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tnfe%2Fclean-state/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tnfe%2Fclean-state/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tnfe%2Fclean-state/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tnfe","download_url":"https://codeload.github.com/tnfe/clean-state/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tnfe%2Fclean-state/sbom","scorecard":{"id":890400,"data":{"date":"2025-08-11","repo":{"name":"github.com/tnfe/clean-state","commit":"a55a83253f61f641663a5778199d9b2a3ec53ecc"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"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":"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":"Code-Review","score":0,"reason":"Found 2/28 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":"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":"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":"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":"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"}},{"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 '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 4 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"}}]},"last_synced_at":"2025-08-24T11:35:52.964Z","repository_id":53611989,"created_at":"2025-08-24T11:35:52.964Z","updated_at":"2025-08-24T11:35:52.964Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30274847,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T20:45:49.896Z","status":"ssl_error","status_checked_at":"2026-03-08T20:45:49.525Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["flux","hooks","mobx","react","react-hooks-module","reducer","redux","state"],"created_at":"2024-08-03T22:00:36.474Z","updated_at":"2026-03-08T21:41:28.814Z","avatar_url":"https://github.com/tnfe.png","language":"TypeScript","funding_links":[],"categories":[":clap: 欢迎参与​"],"sub_categories":["工具库"],"readme":"\u003cp align=\"right\"\u003e\n  \u003cstrong\u003e\n    \u003ca href=\"./README.md\"\u003eEnglish\u003c/a\u003e |\n    \u003ca href=\"./docs/README-zh-cn.md\"\u003e中文\u003c/a\u003e\n  \u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"650px\" src=\"https://github.com/freezeYe/assets/blob/master/cs.png\" /\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n\u003ca href=\"https://www.npmjs.com/clean-state\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/clean-state\" alt=\"Npm Version\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/clean-state\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/npm/l/clean-state?style=flat-square\" alt=\"Package License\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/clean-state\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/clean-state\" alt=\"Downloads\" /\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n## Overview\n🐻 Clean-State is a neat, compact state management tool. It drops all of React's historical baggage, uses native hooks to implement it, and gets rid of Redux's problem of invalid rendering during status updates. At the architectural level it is automatically organized through a very simple API. 🍋 If you're not building an aircraft carrier and you're tired of having a large, complex and unwield-of-use State management library, try clean-state. It is small and exquisite, the performance of the extreme can meet your needs.\n\n## Features\n1.  Using native hooks implementation, zero external dependencies.\n2.  The structure is simple, the module layer granularity is fine and measurable, and the division is clear.\n3.  Excellent performance, can do module level accurate update.\n4.  Native support side effects.\n5.  It's extremely small, just 200 lines of code.\n6.  Just React syntax, zero learning access cost.\n7.  TypeScript friendly and automatically deduces module types.\n8.  Support for Redux - Tool debugging tool.\n9.  Perfect support for RN.\n\n## Installation\n```javascript\nnpm i clean-state --save\n```\n\n## Usage\n#### 1.Define a module\n```javascript\n// modules/user.ts\nconst state = {\n  name: 'test'\n}\n\nconst user = {\n  state,\n  reducers: {\n    setName({payload, state}) {\n      return {...state, ...payload}\n    }\n  },\n  effects: {\n    async fetchNameAndSet({dispatch}) {\n      const name = await Promise.resolve('fetch_name')\n      dispatch.user.setName({name})\n    }\n  }\n}\n\nexport default user;\n```\n\n#### 2.Registration module\n```javascript\n// modules/index.ts\nimport user from './user'\nimport bootstrap from 'clean-state'\n\nconst modules = { user }\nexport const {useModule, dispatch}  = bootstrap(modules);\n```\n\n#### 3.Use the module\n```javascript\n// page.ts\nimport {useCallback} from 'react'\nimport { useModule, dispatch } from './modules'\n\nfunction App() {\n  /** \n   * Here you can also pass in an array and return multiple module states at the same time \n   * const {user, project} = useModule(['user', 'project'])\n   */\n  const { user } = useModule('user')\n  const onChange = useCallback((e)=\u003e {\n    const { target } = e\n    dispatch.user.setName({name: target.value})\n  }, [])\n\n  const onClick = useCallback(()=\u003e {\n    dispatch.user.fetchNameAndSet()\n  }, [])\n\n  return (\n    \u003cdiv className=\"App\"\u003e\n      \u003cdiv\u003e\n        \u003cdiv\u003e\n          name: {user.name}\n        \u003c/div\u003e\n        \u003cdiv\u003e\n          modify: \u003cinput onChange={onChange}\u003e\u003c/input\u003e\n        \u003c/div\u003e\n        \u003cbutton onClick={onClick}\u003egetUserName\u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n\nexport default App;\n```\n\n## Mixin\n\nIn many cases, there are common states, reducers, or effects between multiple modules, and here we expose the methods to prevent users from making duplicate declarations in each module.\n\n```javascript\n// common.ts\nconst common = {\n  reducers: {\n    setValue\u003cState\u003e({payload, state}: {payload: Record\u003cstring, any\u003e, state: State}): State {\n      return {...state, ...payload}\n    }\n  }\n}\nexport default common;\n\n// modules/index.ts\nimport commont from './common'\nimport user from './user'\nimport { mixin } from 'clean-state';\n\n// Mix Common's setValue method into the User module\nconst modules = mixin(common, { user })\n\n// You can now call the dispatch.user.setValue method on other pages\nexport const {useModule, dispatch}  = bootstrap(modules);\n\n```\n\n## Module\n### `state`\nModule state, which is a property object.\n```\n{\n    name: 'zhangsan',\n    order: 1\n}\n```\n### `reducers`\nA collection of handlers that change the state of a module, returning the latest state.\n```\n{\n    setValue({payload, state, rootState}) {\n        return {...state, ...payload}\n    }\n}\n```\n\n### `effects`\nModule's collection of side effects methods that handle asynchronous calls.\n```\n{\n    async fetchAndSetValue({payload, state, rootState, dispatch}) {\n        const newOrder = await fetch('xxx')\n        dispatch.user.setValue({order: newOrder})\n    }\n}\n```\n\n## API\n\n### `bootstrap(modules)`\n| Property | Description | Type |\n| :----: | :----: | :----: |\n| modules | A collection of registered modules | {string, Module} |\n\n### `useModule(moduleName)`\n| Property | Description | Type |\n| :----: | :----: | :----: |\n| moduleName | The name of the module used returns the corresponding status | string / string[] |\n\n### `mixin(common, modules)`\n| Property | Description | Type |\n| :----: | :----: | :----: |\n| common | Public modules that need to be injected | Module |\n| modules | A collection of registered modules | Module |\n\n### `dispatch.{moduleName}.{fnName}(payload)`\n| Property | Description | Type |\n| :----: | :----: | :----: |\n| moduleName | The specific module name of the call should be registered in Bootstrap | string |\n| fnName | The method name of the call module, reducer/effect | string |\n| payload | The load value passed | object |\n\n## Debugging\nYou can use [cs-redux-devtool](https://github.com/freezeYe/cs-redux-devtool) to debug your project and track historical data changes.\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"400px\" src=\"https://github.com/freezeYe/assets/blob/master/redux_devtool.png\" /\u003e\n\u003c/p\u003e\n\n## Notice\n\nDispatch calls take precedence at effects-\u003e reducers, so when there are reducers and effects with the same name under a module, only effects are executed.\n\n## Issues\n\nIf you have better suggestions for this library, or have any problems using it, you can write them here: [https://github.com/tnfe/clean-state/issues](https://github.com/tnfe/clean-state/issues) \n\n## License\n[MIT](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftnfe%2Fclean-state","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftnfe%2Fclean-state","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftnfe%2Fclean-state/lists"}