All Projects → victorgarciaesgi → vuex-typed-modules

victorgarciaesgi / vuex-typed-modules

Licence: other
🧰 A VueX wrapper to fully type your modules without boilerplate!

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to vuex-typed-modules

vuex-analysis
学习源码整体架构系列8篇之vuex源码,前端面试高频源码,微信搜索「若川视野」关注我,长期交流学习~
Stars: ✭ 36 (+2.86%)
Mutual labels:  vuex-plugin
vuex
📚 Mono-repo structure for Vuetify Vuex modules
Stars: ✭ 43 (+22.86%)
Mutual labels:  vuex-plugin
Vuex Orm
The Vuex plugin to enable Object-Relational Mapping access to the Vuex Store.
Stars: ✭ 2,308 (+6494.29%)
Mutual labels:  vuex-plugin
vuex-orm-localforage
Vuex ORM persistence plugin to sync the store against IndexedDB using localforage
Stars: ✭ 51 (+45.71%)
Mutual labels:  vuex-plugin
Vue Wait
Complex Loader and Progress Management for Vue/Vuex and Nuxt Applications
Stars: ✭ 1,869 (+5240%)
Mutual labels:  vuex-store
Vuex Module Decorators
TypeScript/ES7 Decorators to create Vuex modules declaratively
Stars: ✭ 1,714 (+4797.14%)
Mutual labels:  vuex-modules

🧰 vuex-typed-modules

npm version npm downloads npm downloads

A VueX 3 & 4 wrapper that provides type safe hooks and handlers to your Vuex Store modules with less code!

4.x Support Vue 2 & 3, and Vuex 3 & 4 and added composition-api support (Thanks to vue-demi)

3.x Working with Vue 2, and Vue 3 with Vuex4 (but not hooks)

Installation

npm i vuex-typed-modules
#or
yarn add vuex-typed-modules

Usage for version 4.x

Define Module and hook

import { createVuexModule } from 'vuex-typed-modules';

export const [testModule, useTestModule] = createVuexModule({
  name: 'testModule',
  state: {
    count: 1,
  },
  mutations: {
    addCount(state, number: number) {
      state.count += number;
    },
  },
  actions: {
    async addCountAsync(_, count: number): Promise<void> {
      await myAsyncFunction(count);
      // Calling mutation
      testModule.mutations.addCount(count);
    },
  },
});

Module declaration (For 4.x and 3.x)

In your main.ts

import { Database } from "vuex-typed-modules";
import { testModule } from '~modules'

const database = new Database({ logger: true });
const store = new Vuex.Store({
  plugins: [database.deploy([testModule])];
})

// If you're using Vue 3:
createApp(App).use(store).mount("#app");

// If you're using Vue 2:
new Vue({
  store,
  render: h => h(App)
}).$mount("#app");

For Nuxt.js

// store/index.ts
import { Database } from 'vuex-typed-modules';
import { testModule } from '~modules';

const database = new Database({ logger: process.browser });
export const plugins = [database.deploy([testModule])];

export const state = () => ({});

Usage in your components or in other modules!

<template>
  <div class="hello">
    {{ count }}
    <button @click="increment">increment</button>
  </div>
</template>
import { defineComponent, onBeforeUnmount } from 'vue';
import { testModule } from '~/modules';

export default defineComponent({
  name: 'Home',
  setup() {
    const {
      state: { count },
      actions: { increment },
    } = useChildStoreModule();

    return {
      count,
      increment,
    };
  },
});

Note

Store hooks return refs for the state. It can be overwridden by using the option unwrap

With Refs

// You can destructure state when using refs
const {
  state: { count },
} = useTestModule(); // count is of type `Ref<number>`
console.log(count.value);

Without Refs

// If you destructure the state, it will loses reactivity
const { state } = useTestModule({ unwrap: true });
state.count; // count is of type `number`

Dynamic Modules

For dynamic modules, simply use the class VuexDynamicModule instead

import { createVuexDynamicModule } from 'vuex-typed-modules';

export const dynamicModule = createVuexDynamicModule({
  name: 'dynamicModule',
  logger: false,
  state: {
    count: 1,
    type: null,
  },
  actions: {
    // Due to limitions of Typescript, I can't provide typings for infered mutations and getters inside the same object.
    // It would make an infinite loop (I tried).
    // For dynamic module you can fallback on "commit" "dispatch" and "getters"
    exemple({ state, commit, dispatch, getters }, param: string) {
      // ...
    },
  },
});

Usage

<script lang="ts">
import { defineComponent, onBeforeUnmount } from 'vue';
import { dynamicModule } from '~/modules';

const [ChildStoreModule, useChildStoreModule] = dynamicModule.instance('child-store');
// Dot not declare it in other files, only import it from here

export default defineComponent({
  name: 'TestView',
  setup() {
    ChildStoreModule.register();
    const {
      state: { count },
    } = useChildStoreModule();

    onBeforeUnmount(() => {
      ChildStoreModule.unregister();
    });

    return {
      count,
    };
  },
});
</script>

Default module helpers

Vuex types modules also add helpers functions on top of your module to prevent from writing short mutations

testModule.resetState();
// Reset your module to the initial State
// You can specify only the property you want to update
testModule.updateState({
  count: 3,
});

// You can also give a callback function to have access to the current state
testModule.updateState((state) => ({
  count: state.count + 2,
}));

// And also mutate the state directly (A bit heavier on the update)
testModule.updateState((state) => {
  state.count++;
});

-------------------------------------------

Usage for 3.x

Define Module

Create a test.module.ts in your store folder

import { VuexModule } from 'vuex-typed-modules';

export const testModule = new VuexModule({
  name: 'testModule',
  state: {
    count: 1,
  },
  mutations: {
    addCount(state, number: number) {
      state.count += number;
    },
  },
  actions: {
    async addCountAsync(_, count: number): Promise<void> {
      await myAsyncFunction(count);
      // Calling mutation
      testModule.mutations.addCount(count);
    },
  },
});

Usage in your components or in other modules!

<template>
  <div class="hello">
    {{ count }}
    <button @click="increment">increment</button>
  </div>
</template>
import { Component, Prop, Vue } from 'vue-property-decorator';
import { testModule } from '~/modules';

@Component
export default class Home extends Vue {
  get count() {
    return testModule.getters.count;
  }

  async increment() {
    await testModule.actions.addCountAsync(2);
  }
}

Tests

// user.spec.ts
import { createTestStore } from 'vuex-typed-modules';
import { createLocalVue } from '@vue/test-utils';
// import state, actions, mutations and getters from some store module

const configStore = {
  state,
  actions,
  mutations,
  getters,
};

const localVue = createLocalVue();
localVue.use(Vuex);

const store = createTestStore(configStore);

describe('User Module', () => {
  it('name should be empty', () => {
    expect(store.state.name).toBe('');
  });
  it('name should change to Foo', () => {
    store.dispatch('CHANGE_NAME', 'Foo');
    expect(store.state.name).toBe('Foo');
  });
});
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].