{"id":23821263,"url":"https://github.com/niqingyang/mobx-react-stores","last_synced_at":"2026-05-04T11:39:07.504Z","repository":{"id":57299676,"uuid":"191968629","full_name":"niqingyang/mobx-react-stores","owner":"niqingyang","description":"mange react stores by mobx","archived":false,"fork":false,"pushed_at":"2019-12-04T15:27:53.000Z","size":31,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-10-21T08:26:00.936Z","etag":null,"topics":["mobx","react","router","stores"],"latest_commit_sha":null,"homepage":"https://acme.top/mobx-react-stores-doc","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/niqingyang.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":"2019-06-14T15:41:47.000Z","updated_at":"2019-12-04T15:28:14.000Z","dependencies_parsed_at":"2022-08-26T21:50:15.535Z","dependency_job_id":null,"html_url":"https://github.com/niqingyang/mobx-react-stores","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/niqingyang/mobx-react-stores","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niqingyang%2Fmobx-react-stores","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niqingyang%2Fmobx-react-stores/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niqingyang%2Fmobx-react-stores/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niqingyang%2Fmobx-react-stores/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/niqingyang","download_url":"https://codeload.github.com/niqingyang/mobx-react-stores/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niqingyang%2Fmobx-react-stores/sbom","scorecard":{"id":688723,"data":{"date":"2025-08-11","repo":{"name":"github.com/niqingyang/mobx-react-stores","commit":"59568d385f96ab7b2c2e0578a699ed5dd66b1402"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"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":"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":"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":"Code-Review","score":0,"reason":"Found 0/12 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":"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":"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":"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":"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":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: 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":"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"}}]},"last_synced_at":"2025-08-22T01:43:50.875Z","repository_id":57299676,"created_at":"2025-08-22T01:43:50.876Z","updated_at":"2025-08-22T01:43:50.876Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32606405,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-04T10:08:07.713Z","status":"ssl_error","status_checked_at":"2026-05-04T10:08:02.005Z","response_time":58,"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":["mobx","react","router","stores"],"created_at":"2025-01-02T08:36:24.379Z","updated_at":"2026-05-04T11:39:07.471Z","avatar_url":"https://github.com/niqingyang.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## mobx-react-stores\n\nmobx-react-stores 是为了方便将 antd pro 改为使用 mobx 而开发的，里面的思路和代码大量的参考了 dva 和 umi 的实现，mobx 版的 antd pro 并且全功能版的将于不久开源，即基于此库\n\n具体使用方式请参考文档：[https://acme.top/mobx-react-stores-doc](https://acme.top/mobx-react-stores-doc)\n\n## 安装\n\n```shell\nnpm i mobx-react-stores\n```\n\n## 使用\n\n获取 `stores` 实例对象\n\n```js\nimport {stores} from 'mobx-react-stores';\n```\n\n### 状态管理\n\nmobx-react-stores 可以用作状态管理，也是其最核心的目的，接口设计的比较简单，主要就两个：\n\n1. **stores.add(model: object | Promise, namespaceAlias: null | string)** - 用来向 `stores` 注入待管理的 `model` 对象\n\n- 参数 `model` 如果为对象则必须包含一个 string 类型的 `namespace` 属性，用作其在 `stores` 中的唯一标识，也就是 `stores` 中的属性名称\n- 参数 `model` 也可以为一个 `Promise` 对象，`Promise` 必须返回一个包含 string 类型的 `namespace` 属性\n- 参数 `namespaceAlias` 可选，用来为 `model` 起别名，如果存在则 `model` 可以不包含 `namespace` 属性\n\n2. **dispatch({type, payload})** - 类似 `dva` 的 `dispatch`，用来通过 `namespace/action` 这种形式快速访问 `model` 对象中的函数\n\n- 参数 `type` 为字符串类型，格式为 `namespace/action`\n- 参数 `payload` 为任意类型，可选，用于向所调用的函数中传递参数，`namespace/action` 函数接收到的参数就是 `payload`\n- `dispatch` 一般直接被注入到了上下文中，方便组件调用\n\n### 监听加载状态\n\n`mobx-loading` 能实现类似 dva-loading 的效果，方便监听 model 及其 action 的执行状态，减少开发人员对组件 `show` `hide` 的操作\n\n- 获取 loadingStore 对象的方法\n\n```js\nimport {loadingStore} from 'mobx-loading'\n```\n\nmobx-react-stores 默认集成了 mobx-loading，作为 stores 的内置属性，namespace 为 `loading`，所以可以直接从 stores 中获取 loadingStore 对象\n\n```js\nconst {loading} = stores;\n```\n\n- 使用方式\n\n```js\n// 通过 actions 获取指定 namespace/action 的当前加载状态\nloading.actions['goods/fetchList']\n\n// 通过 models 获取指定 namespace 的当前加载状态\n// namespace 下任何 action 加载状态为 true，则此 namespace 的加载状态即为 true\nloading.models.goods\n\n// 通过 global 获取全局的加载状态\n// 只要任何一个 model 的状态为 true，则 global 的状态即为 true\nloading.global\n\n// 从 mobx-react-stores 和 mobx-loading 中都可以获取 namespace 装饰器\n// 用作 class，方便向 class 中注入 namespace 属性\nimport {namespace} from 'mobx-loading';\nimport {namespace} from 'mobx-react-stores';\n```\n\n- 使用示例\n\n```js\n// 获取 namespace 和 loading 装饰器\nimport {namespace, loading} from 'mobx-react-stores';\nimport {fetchRandomUser} from \"@/services/demo\";\n\n// 默认会为 class 添加 namespace 属性，**必须指明，否则JS压缩后会导致丢失namespace**\n// 此处 namespace 值为 randomUser\n@namespace(\"randomUser\")\nclass RandomUser {\n\n    user;\n\n    message;\n\n    // 通过 loading 装饰器，向 loadingStore 中注入当前 action 的加载状态\n    @loading\n    fetchUser = async () =\u003e {\n\n        this.user = null;\n        this.message = null;\n\n        const response = await fetchRandomUser().catch(this.onRejected);\n\n        if (response.results) {\n            const user = response.results[0];\n\n            this.change({\n                user: {\n                    name: `${user.name.first} ${user.name.last}`,\n                    email: user.email,\n                    picture: user.picture.large\n                },\n                message: null\n            });\n        }\n    }\n\n    change = ({user, message}) =\u003e {\n        this.user = user;\n        this.message = message;\n    }\n\n    onRejected = (e) =\u003e {\n        return {\n            status: 500,\n            message: e.message\n        }\n    }\n}\n\nexport default new RandomUser();\n\n// -----------------------RandomUser.js--------------------------------\n\nimport React from 'react';\nimport {inject} from 'mobx-react'\n\n@inject(({stores: {dispatch, loading, randomUser}}) =\u003e {\n    return {\n        dispatch,\n        randomUser,\n        loading: loading.models.randomUser\n    }\n})\nclass RandomUser extends React.PureComponent {\n\n    onFetchUser = () =\u003e {\n        const {dispatch} = this.props;\n        dispatch({\n            type: 'randomUser/fetchUser'\n        })\n    }\n\n    render() {\n        const {loading, randomUser} = this.props;\n\n        if (loading) {\n\t\t\t// do someting\n\t\t}else{\n\t\t\tconst {user, message} = randomUser;\n\t\t\t// do someting\n\t\t}\n\t}\n}\n\nexport default RandomUser;\n\n```\n\n-  **@loading(names: string | array | null)** - loading 装饰器作用于 model 内的函数，可以接收字符串和数组的参数\n\n- 例如： @loading('randomUser/fetchList')、@namespace(['randomUser', 'fetchList']) 与上面的示例代码结果一样\n\n- `loading` 装饰器优先使用当前 class 的 namespace 属性和 函数的名称（首字母小写）生成此 action 的唯一标识，无 namespace 属性则使用 class 的名称（首字母小写）。上门示例中 loading 无参则其函数的加载状态可由 `loadingStore.actions['randomUser/fetchList']` 取得\n\n\u003c!--begin.warning--\u003e\n\n\u003e 上面示例中的 loading 是装饰器，与 stores.loading 不同。stores.loading 是 loadingStore 注入 stores 后的属性\n\n\u003c!--end.warning--\u003e\n\n### 路由管理\n\n为了方便管理路由以及向 stores 中注入 model，mobx-react-stores 提供了类似 umi 管理路由的方法，不过没有像 umi 那样去生成临时文件，而是更直接的方式\n\n\u003c!--begin.tip--\u003e\n\n\u003e 建议在 `src` 目录下新建 `default.router.js` 文件来存放路由，如果模块多而复杂，可以将各个模块的路由分散开来然后聚合到这个文件中\n\n\u003c!--end.tip--\u003e\n\n**路由示例**\n\n```js\nexport default [\n    // user\n    {\n        path: '/user',\n\t\t// 布局文件\n        component: () =\u003e import('./layouts/UserLayout'),\n\t\tLoadingComponent = require('./components/PageLoading').default，\n\t\tRoutes: [require('./pages/Authorized').default],\n        authority: ['admin', 'user'],\n        routes: [\n\t\t\t// 从 /user 重定向到 /user/login\n            {path: '/user', redirect: '/user/login'},\n            {path: '/user/login', name: 'login', component: () =\u003e import('./pages/User/Login')},\n            {\n                name: 'register',\n                path: '/user/register',\n                models: () =\u003e [import('./pages/User/models/register')],\n                component: () =\u003e import('./pages/User/Register')\n            },\n            {\n                name: 'register.result',\n                path: '/user/register-result',\n                component: () =\u003e import('./pages/User/RegisterResult'),\n            },\n        ],\n    }\n]\n```\n\n- **name** - 路由名称，用于生成菜单，name 和 path 都存在的才会生成菜单 ~ Antd Pro 这么定义的\n- **path** - 路由的路径\n- **models** - model 对象集合，支持按需加载，会与 component 一同加载，支持：`() =\u003e [import('xxx/model1'), import('xxx/model2')]`、`() =\u003e import('xxx/model1')`、`[() =\u003e import('xxx/model1'), () =\u003e import('xxx/model2')]` 等形式。主要方便于子路由的 models 和上级路由 models 进行数组合并，一些公共的 models 可以放在上级路由中，方便管理。\n- **component** - 组件，如果有下级路由，则是下级路由的布局文件，支持异步按需加载（需提供一个函数，类似：`()=\u003eimport('xxxx')）`\n- **LoadingComponent** - 异步按需加载组件时的加载效果组件\n- **Routes** - 方便自定义权限校验路由，可参考 Antd Pro 去实现\n- **authority** - 访问路由所需的权限，用于权限校验，可参考 Antd Pro 去实现\n- **routes** - 子路由集合\n\n**使用路由**\n\n```js\nimport {formatterRoutes, renderRoutes} from 'mobx-react-stores';\nimport router from './default.router.js';\n\n// ... do someting\n\n// 格式化\nconst routes = formatterRoutes(this.router, this.stores);\n// 渲染路由\nlet children = renderRoutes(routes);\n\nreturn (\n\t\u003cRouter history={history}\u003e\n\t\t{children}\n    \u003c/Router\u003e\n);\n\n// ... do someting\n```\n\n### 国际化\n\nmobx-react-stores 推荐使用 react-intl 来管理国际化\n\n注入 Locale\n\n```js\nimport {stores, Locale} from 'mobx-react-stores';\n\n// ... do someting\n\n// 可参考 Antd Pro\nconst translations = {\n    'en-US': {\n        messages: {\n            ...require('../locales/en-US.js').default,\n        },\n        locale: 'en-US',\n        antd: require('antd/lib/locale-provider/en_US'),\n        data: require('react-intl/locale-data/en'),\n        momentLocale: '',\n    },\n    'zh-CN': {\n        messages: {\n            ...require('../locales/zh-CN.js').default,\n        },\n        locale: 'zh-CN',\n        antd: require('antd/lib/locale-provider/zh_CN'),\n        data: require('react-intl/locale-data/zh'),\n        momentLocale: 'zh-cn',\n    },\n\t// ... 其他语言包\n};\n\n// 注入\nstores.add(new Locale('zh-CN', translations), \"locale\");\n\n// ... do someting\n```\n\n**切换语言**\n\n```js\nstores.locale.change('zh-CN');\n\n// 或者\n\ndispatch({\n\ttype: 'locale/change',\n\tpayload: 'zh-CN'\n});\n```\n\n## 集成\n\n为了简化开发，方便使用 国际化、history 等，mobx-react-stores 提供了集成好的接口\n\n**使用示例**\n\n在 `src` 目录下新建 `index.js` 文件作为入口文件\n\n```js\n// 兼容 IE9、IE10 ~ 如果需要的话请解开封印\n// import 'react-app-polyfill/ie9';\n// import 'react-app-polyfill/stable';\nimport React from 'react';\nimport {LocaleProvider} from 'antd';\nimport {app} from 'mobx-react-stores';\nimport get from 'lodash/get';\nimport './utils/axios'; // 初始化拦截器\nimport './global.less';\nimport * as serviceWorker from './serviceWorker';\n\napp.stores = require('./models').default;\napp.router = require('./default.router').default;\n\napp.defaultLoadingComponent = require('./components/PageLoading').default;\n\n// 渲染时回调，方便一些额外的操作，比如注入 antd 的国际化\napp.renderCallback = (children) =\u003e {\n\n    const {locale} = app.stores;\n\n    const antd = get(app.stores, 'locale.translation.antd', undefined);\n\n    if (antd) {\n        return (\n            \u003cLocaleProvider locale={antd.default || antd}\u003e\n                {children}\n            \u003c/LocaleProvider\u003e\n        );\n    }\n\n    return children;\n};\n\napp.render(document.getElementById('root'));\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://bit.ly/CRA-PWA\nserviceWorker.unregister();\n```\n\n**集成后**\n\n- **stores** 中将获得 `intl`、`routing` 两个对象，可用于国际化和操作路由\n- **intl** 是 react-intl 注入后的实例对象，可使用 `intl.formatMessage()` 等函数\n- **routing** 可以实现 `routing.push()`、`routing.replace()` 等路由操作\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniqingyang%2Fmobx-react-stores","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniqingyang%2Fmobx-react-stores","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniqingyang%2Fmobx-react-stores/lists"}