{"id":21320067,"url":"https://github.com/xieyezi/genji","last_synced_at":"2026-07-18T05:01:45.700Z","repository":{"id":57141947,"uuid":"366667580","full_name":"xieyezi/genji","owner":"xieyezi","description":"a vue state management framewok by vue3 reactivity","archived":false,"fork":false,"pushed_at":"2022-05-12T14:37:35.000Z","size":394,"stargazers_count":14,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-04T23:49:06.166Z","etag":null,"topics":["compostion-api","hooks-api","hookstate","management","state-management","vue-hooks","vue3","vue3-reactivity"],"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/xieyezi.png","metadata":{"files":{"readme":"README-CN.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-05-12T09:48:46.000Z","updated_at":"2024-02-24T07:27:48.000Z","dependencies_parsed_at":"2022-09-15T05:41:22.754Z","dependency_job_id":null,"html_url":"https://github.com/xieyezi/genji","commit_stats":null,"previous_names":["xieyezi/juefei"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/xieyezi/genji","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xieyezi%2Fgenji","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xieyezi%2Fgenji/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xieyezi%2Fgenji/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xieyezi%2Fgenji/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xieyezi","download_url":"https://codeload.github.com/xieyezi/genji/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xieyezi%2Fgenji/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264939475,"owners_count":23686206,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["compostion-api","hooks-api","hookstate","management","state-management","vue-hooks","vue3","vue3-reactivity"],"created_at":"2024-11-21T19:44:58.226Z","updated_at":"2026-07-18T05:01:40.664Z","avatar_url":"https://github.com/xieyezi.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"320\" height=\"320\" src=\"genji.png\" /\u003e\n\u003c/p\u003e\n\n\nLanguage: 中文简体 | [EN](https://github.com/xieyezi/genji)\n\n\n\u003ccode\u003e![visitors](https://visitor-badge.glitch.me/badge?page_id=xieyezi.genji)\u003c/code\u003e\n\u003ccode\u003e![bundle size](https://img.shields.io/badge/bundle--size-2k-blue)\u003c/code\u003e\n\u003ccode\u003e![npm-version](https://img.shields.io/npm/v/@xieyezi/genji)\u003c/code\u003e\n\u003ccode\u003e![coverage](https://img.shields.io/badge/coverage-100%25-blue)\u003c/code\u003e\n\n\n\n`genji` 是一个轻巧的基于 `@vue-reactivity` 开发的 `vue3` 状态管理框架.\n\n### 为什么被称作 genji ?\n灵感来自于游戏`《守望先锋》` 的游戏角色：`源氏`。\n\n源氏可以用致命而准确的手里剑重创敌人，他的高科技武士刀可以用来反弹敌人的远程攻击，或是对敌人施展一次快速攻击。\n\n所以 `genji` 是快速的、敏捷的、准确的！\n\n```\npnpm install @xieyezi/genji\n```\n\n### 创建一个Store\n\n你的 `Store` 是一个基于`compostion-api` 的 `hook`！您可以在其中添加任何内容：普通类型，对象，函数。 `set` 函数会将他们合并为一个 `Store`。\n\n```ts\nimport { create } from '@xieyezi/genji'\n\nconst useStore = create((set, get) =\u003e ({\n  count: 0,\n  increase: () =\u003e set(state =\u003e ({ count: state.count + 1 })),\n  resetCount: () =\u003e set({ count: 0 })\n}))\n```\n### 然后就可以在组件里面使用它了，就是如此简单!\n\n在你的组件中使用这个 `hook`，取出你想要的值，组件将在更新 `state` 之后重新渲染。\n\n```ts\n\u003ctemplate\u003e\n  \u003cp\u003ecount is: {{ count }}\u003c/p\u003e\n  \u003cbutton @click=\"increase\"\u003ecount++\u003c/button\u003e\n\u003c/template\u003e\n....\nsetup() {\n  const { count, increase } = useStore(state =\u003e ({\n   count: state.count,\n   increase: state.increase\n  }))\n\n  return {\n    count,\n    increase,\n  }\n}\n```\n\n### 从Store中取值\n\n你可以按照自己喜欢的方式取出你想要的值。\n\n如果你想一个一个取出来:\n\n```ts\nconst count = useStore(state =\u003e state.count)\nconst genji = useStore(state =\u003e state.genji)\n```\n\n如果你想用对象的方式取值（类似`vuex mapState`）:\n\n```ts\n// Object pick, re-renders the component when either state.count or state.genji change\nconst { count, genji } = useStore((state) =\u003e ({\n  count: state.count,\n  genji: state.genji\n}))\n```\n\n如果你想用数组的方式取值（类似`react hooks`）:\n\n```ts\n// Array pick, re-renders the component when either state.count or state.genji change\nconst [count, genji] = useStore(state =\u003e [state.count, state.genji])\n```\n\n甚至你还可以不带任何参数，直接取出来:\n```ts\n// uses the store with no args\nconst { count, increase } = useStore()\n```\n\n所有取值方式都是如此简单！这一切都取决于你怎么创建你的`选择器`。\n\n### 从多个Store中取值\n\n由于你可以创建任意数量的 `Store`，因此你可以随意组合各个`Store` 里面的值。\n\n```ts\nimport useUserStore from '../store/user'\nimport useOrder from '../store/order'\n\nconst name = useUserStore(state =\u003e state.name)\nconst orders = useOrder(state =\u003e state.orders)\n\n```\n\n### 带有计算属性的选择器\n\n在 `vue` 中，通常来说，一般都建议利用 `computed`来构造你的选择器。\n\n\u003e 但是需要注意，此时从 `Store` 中选择的值需要用 `unref` 包装，因为状态的值由 `Proxy` 代理。\n\n\n```ts\nconst countDouble = useStore(state =\u003ecomputed(()=\u003eunref( state.count) * 2))\n```\n\n如果`选择器`不在组件中使用，则也可以在组件外部定义它。但是，当使用来自 `Store` 的选择值时，也需要使用 `unref` 进行包裹，或者你也可以直接利用 `.value` 来使用它。\n\n```ts\nconst selector = state =\u003e state.hero\nconst hero = useStore(selector)\n\n// warpped with unref()\nconsole.log(unref(hero))\n\n// or you can use like this:\nconsole.log(hero.value)\n\n```\n\n### 变更Store\n\n`genji` 提供 `set` 函数来更新“状态”。就像这样：\n\n```ts\nconst useStore = create((set, get) =\u003e ({\n  count: 0,\n  increase: () =\u003e set(state =\u003e ({ count: state.count + 1 })),\n}))\n\nconst { count, increase } = useStore(state =\u003e ({\n  count: state.count,\n  increase: state.increase\n}))\n```\n接着你就可以使用 `increase` 函数去改变 `count`。\n\n### Async actions\n\n\u003e 对于异步任务，建议使用 `async/await` 来处理。\n\n```ts\nconst useStore = create((set, get) =\u003e ({\n   userInfo: {},\n   getUserInfo: async () =\u003e {\n      const res = await fetch(pond)\n      set({ userInfo: res })\n   }\n}))\n```\n### 在 `action` 中读取 `Store`\n\n在一个 `action` 执行过程中，如果你想取出 `Store` 的某些值，你可以通过 `get` 钩子来访问`Store`。\n\n```ts\nconst useStore = create((set, get) =\u003e ({\n  hero: 'genji',\n  action: () =\u003e {\n    const hero = get().hero\n    // ...\n  }\n})\n```\n\n### TypeScript支持\n\n```ts\n// 可以使用 `type`\ntype State = {\n  count: number\n  increase: (by: number) =\u003e void\n}\n\n// 或者 `interface`\ninterface State {\n  count: number\n  increase: (by: number) =\u003e void\n}\n\n// 然后所有的类型都会被正确推导\nconst useStore = create\u003cState\u003e(set =\u003e ({\n  count: 0,\n  increase: (by) =\u003e set(state =\u003e ({ count: state.count + by })),\n}))\n```\n\n喜欢你能喜欢`genji`~\n\n\u003e api usage inspired by zustand, thanks a lot!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxieyezi%2Fgenji","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxieyezi%2Fgenji","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxieyezi%2Fgenji/lists"}