{"id":13511371,"url":"https://github.com/ElMassimo/vuex-stores","last_synced_at":"2025-03-30T20:33:05.174Z","repository":{"id":47847540,"uuid":"262918520","full_name":"ElMassimo/vuex-stores","owner":"ElMassimo","description":"🗄 Store objects for Vuex, a simple and more fluid API for state-management.","archived":false,"fork":false,"pushed_at":"2021-10-28T01:23:13.000Z","size":1355,"stargazers_count":63,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-27T08:59:22.279Z","etag":null,"topics":["js","maintainability","vue","vuex","vuex-modules","vuex-plugin","vuex-store","vuex2","vuex3"],"latest_commit_sha":null,"homepage":"https://maximomussini.com/posts/vuex-stores","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/ElMassimo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-11T02:23:42.000Z","updated_at":"2025-01-09T16:41:49.000Z","dependencies_parsed_at":"2022-09-11T00:11:01.742Z","dependency_job_id":null,"html_url":"https://github.com/ElMassimo/vuex-stores","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElMassimo%2Fvuex-stores","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElMassimo%2Fvuex-stores/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElMassimo%2Fvuex-stores/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ElMassimo%2Fvuex-stores/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ElMassimo","download_url":"https://codeload.github.com/ElMassimo/vuex-stores/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246379372,"owners_count":20767694,"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":["js","maintainability","vue","vuex","vuex-modules","vuex-plugin","vuex-store","vuex2","vuex3"],"created_at":"2024-08-01T03:00:48.540Z","updated_at":"2025-03-30T20:33:04.853Z","avatar_url":"https://github.com/ElMassimo.png","language":"JavaScript","funding_links":[],"categories":["vue"],"sub_categories":[],"readme":"\u003e Prefer [pinia](https://github.com/posva/pinia) if using Vue 3 or `@vue/composition-api` in Vue 2\n\n# Vuex Stores 🗄\n\n[![Gem Version](https://badge.fury.io/js/vuex-stores.svg)](http://badge.fury.io/js/vuex-stores)\n[![Build Status](https://travis-ci.org/ElMassimo/vuex-stores.svg)](https://travis-ci.org/ElMassimo/vuex-stores)\n[![Code Climate](https://codeclimate.com/github/ElMassimo/vuex-stores/badges/gpa.svg)](https://codeclimate.com/github/ElMassimo/vuex-stores)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ElMassimo/vuex-stores/blob/master/LICENSE.txt)\n\nStore objects for Vuex 3, a simple and more fluid API for state-management.\n\n## Why? 🤔\n\nDispatching actions and injecting getters in [Vuex](https://vuex.vuejs.org/) requires using `String`\nnamespaces and action names, which is verbose and makes it hard to detect typos.\n\nInjecting state, getters, and actions using the `map` helpers is sometimes\ncumbersome, and is only suitable for components.\n\nStore objects address these issues by allowing access to state and getters as\nproperties, and dispatching actions easily by using plain method calls.\n\nRead more about the benefits in the [blog announcement](http://maximomussini.com/posts/vuex-stores).\n\n## Installation ⚙️\n\n```\nnpm install --save vuex-stores\n```\n\nor if using `yarn`:\n\n```\nyarn add vuex-stores\n```\n\n## API ⌨️\n\n`registerAndGetStore` allows to [dynamically register](https://vuex.vuejs.org/guide/modules.html#dynamic-module-registration) a [module](https://vuex.vuejs.org/guide/modules.html) in the specified\nVuex store, returning a _Store Object_ which can be used to easily access state,\ngetters, and actions, abstracting away the namespace for that module.\n\n```js\nimport { registerAndGetStore } from 'vuex-stores'\n\nconst WindowStore = registerAndGetStore(vuexStore, { namespace, state, getters, mutations, actions })\n````\n\n### [State](https://vuex.vuejs.org/guide/state.html) 🗃\n\nState can be accessed as properties in the store object:\n\n```js\nconst state = {\n  isFullscreen: false,\n  windowHeight: 768,\n  windowWidth: 1024,\n}\n\n// A property is available for every property in the state:\n\nWindowStore.isFullscreen // false\nWindowStore.windowHeight // 768\nWindowStore.windowWidth // 1024\n\n// instead of\n\nthis.$store.state.window.windowWidth // ❌\n```\n\n### [Getters](https://vuex.vuejs.org/guide/getters.html) ✋\n\nGetters can be accessed as properties in the store object:\n\n```js\nconst getters = {\n  windowSize (state) {\n    return state.windowHeight * state.windowWidth\n  },\n}\n\n// A property is available for every getter:\n\nWindowStore.windowSize // 1024 * 768 = 786,432\n\n// instead of\n\nthis.$store.getters['window/windowSize'] // ❌\n```\n\n### [Actions](https://vuex.vuejs.org/guide/actions.html) ⚡️\n\nActions can be dispatched by calling methods in the store object:\n\n```js\nexport const actions = {\n  setFullscreen ({ commit }, isFullscreen) {\n    commit('SET_FULLSCREEN', isFullscreen)\n  },\n  updateWindowSize ({ commit }, size = { height: window.innerHeight, width: window.innerWidth }) {\n    commit('SET_WINDOW_SIZE', size)\n  },\n}\n\n// A method is available for every action:\nWindowStore.setFullscreen(true)\nWindowStore.updateWindowSize()\nWindowStore.updateWindowSize({ width: 1024, height: 768 })\n\n// instead of\nthis.$store.dispatch('window/updateWindowSize', { width: 1024, height: 768 }) // ❌\n```\n\nBy convention, mutations should be an internal detail, so they are not exposed.\n\n### `mapState`, `mapGetters`, `mapActions`\n\nThese usual helpers are available, allowing us to inject properties and methods\nin a component, without having to [deal with the namespace](https://vuex.vuejs.org/guide/modules.html#binding-helpers-with-namespace):\n\n```js\ncomputed: {\n  ...WindowStore.mapState('windowHeight', 'windowWidth'),\n  ...WindowStore.mapGetters('windowSize'),\n},\nmethods: {\n  ...WindowStore.mapActions('setFullscreen')\n},\n```\n\nThese are mostly helpful when the values are used in the template. Else, we have\na better option:\n\n```js\nmethods: {\n  onToggleFullscreen (event) {\n    WindowStore.setFullscreen(!WindowStore.isFullscreen)\n  },\n},\n```\n\nAn additional benefit is that references to the state and actions are more\nexplicit, and don't require [manual boilerplate](https://vuex.vuejs.org/guide/mutations.html#using-constants-for-mutation-types), making the code easier to understand and refactor 😀\n\n### [`watch`](https://vuex.vuejs.org/api/#watch) 👁\n\nMakes it convenient to watch a store value outside the component lifecycle:\n\n```js\nWindowStore.watch('windowSize', windowSize =\u003e console.log('onWindowSizeChange', windowSize))\n\nWindowStore.watch('isNavigating',\n  isNavigating =\u003e isNavigating ? NProgress.start() : NProgress.done(),\n  { sync: true }, // Any watcher options can be provided, such as `immediate`.\n)\n```\n\nOther less commonly used API properties and methods include:\n\n- `buildStoreObject`: Like `registerAndGetStore`, but doesn't call `registerModule`.\n- `registerModule`: Used internally by `registerAndGetStore` to register the module in Vuex.\n- `unregisterModule`: Can be used to remove the module from the Vuex store.\n- `moduleNamespace`: The module name for this store object in the Vuex store, relevant if using a [factory pattern](https://github.com/ElMassimo/vuex-stores#dynamic-stores-factory-).\n\n## Recommended Setup 🛠\n\nThe recommended setup involves exporting the `Vuex.Store`:\n\n```js\n// @app/store.js\n\nimport Vue from 'vue'\nimport Vuex from 'vuex'\n\nVue.use(Vuex)\n\nexport default new Vuex.Store({\n  strict: process.env.NODE_ENV !== 'production'\n})\n```\n\nAnd creating [one file](https://github.com/ElMassimo/vuex-stores/blob/master/tests/stores/ModalsStore.js) per store module, [exporting the store object](https://github.com/ElMassimo/vuex-stores/blob/master/tests/stores/WindowStore.js#L45).\n\n```js\n// @stores/ModalStore.js\n\nimport VuexStore from '@app/store'\nimport { registerAndGetStore } from 'vuex-stores'\n\nconst namespace = 'modals'\nconst state = () =\u003e ({ ... })\nconst getters = { ... }\nconst mutations = { ... }\nconst actions = { ... }\n\nexport default registerAndGetStore(VuexStore, { namespace, state, getters, mutations, actions })\n```\n\nThis makes it very convenient to import the [store object](https://github.com/ElMassimo/vuex-stores/blob/master/tests/stores/ModalsStore.js) from a component:\n\n```vue\n// @components/ModalManager.vue\n\n\u003cscript\u003e\nimport ModalsStore from '@stores/ModalsStore'\n\nexport default {\n  name: 'ModalManager',\n  computed: ModalsStore.mapState('modals'),\n  beforeMount () {\n    // Hide modals when visiting a different route.\n    if (this.$router) this.$router.afterEach(ModalsStore.closeAllModals)\n  },\n  methods: {\n    onModalClose (modal, event) {\n      if (!event.defaultPrevented) ModalsStore.removeModal(modal)\n    },\n  },\n}\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n  \u003cspan class=\"modal-manager\"\u003e\n    \u003ccomponent\n      :is=\"modal.component\"\n      v-for=\"modal in modals\"\n      :key=\"modal.id\"\n      v-bind=\"modal.attrs\"\n      v-on=\"modal.listeners\"\n      @modal:close.native=\"onModalClose(modal, $event)\"\n    /\u003e\n  \u003c/span\u003e\n\u003c/template\u003e\n```\n\nFeel free to check the [tests](https://github.com/ElMassimo/vuex-stores/blob/master/tests/components/WindowDisplay.vue)\nfor additional usage examples, and setup options.\n\n### Dynamic Stores (Factory) 💠\n\nWhat happens if we need more than one instance of a store? Instead of exporting\na single store object, we can export a function that dynamically registers a new\nstore object on each invocation. For example:\n\n```js\n// @stores/FormStoreFactory\nlet formId = 0\n\nexport default (id = `form-${formId++}`) =\u003e\n  registerAndGetStore(store, { namespace: id, state, getters, mutations, actions })\n```\n\nAnd then import the factory:\n\n```js\nimport FormStoreFactory from '@stores/FormStoreFactory'\n\n// A new module is registered with a dynamic namespace.\nconst FormStore = FormStoreFactory()\n```\n\nThese dynamic store objects can be passed to child components using `provide` and\n`inject`, or directly as props, and provide all the advantages from Vuex, such\nas a well defined data-schema for the state, and having the history of changes\navailable in the Vue devtools, making it very convenient for complex hierarchies.\n\nYou can call `registerModule` and `unregisterModule` on the store object to\nmanage the lifecycle, unregistering them once they are no longer necessary to\nfree up some memory.\n\n### Farewell\n\nThe patterns described above are just a few of many possibilities.\n\nNothing prevents you from using a more complex strategy, like [creating a store\nof stores](https://imgflip.com/i/412qhj), which has a `Map` of store objects,\nand uses actions to register and unregister new store objects ♻️\n\nLet me know if you come up with new or creative ways to use it 😃\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FElMassimo%2Fvuex-stores","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FElMassimo%2Fvuex-stores","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FElMassimo%2Fvuex-stores/lists"}