Dynamic vuex store modules with NuxtJS and vuex-module-decorators
Asked Answered
S

4

7

I'm having a hard time making my vuex modules work with NuxtJS SSR, TypeScript and vuex-module-decorators.

I tried following guide from the official nuxt website and the vuex-module-decorators, but nothing works...

Here's my code :

// store/CommonModule.ts
import { Module, VuexModule, Mutation } from 'vuex-module-decorators'

@Module({
  name: 'CommonModule',
  namespaced: true,
  stateFactory: true,
})
export default class CommonModule extends VuexModule {
  message: string = 'hi'

  @Mutation
  public SET_MESSAGE(val: string) {
    this.message = val
  }
}
// store/index.ts
import Vuex from 'vuex'
import CommonModule from '~/store/CommonModule'

export function createStore() {
  return new Vuex.Store({
    modules: {
      CommonModule,
    },
  })
}
// components/Home.vue
import { Component, Vue } from 'vue-property-decorator';
import { getModule } from 'vuex-module-decorators';
import CommonModule from '~/store/CommonModule'

@Component
export default class Home extends Vue {
    get message(): string {
        const commonModule = getModule(CommonModule, this.$store)
        return commonModule.message // throws an error: Cannot read property 'message' of undefined
    }
}

Whenever I try to access anything in my modules, these are undefined...

I know this approach is "static modules". My goal is to use dynamic modules, but if the static modules are the only way to make this work with NuxtJS SSR, it'll be fine.

Any help will be greatly appreciated. Thanks :)

EDIT
I gave up and used vuex-class-component

Supinate answered 21/2, 2020 at 13:51 Comment(3)
Did you end up finding an answer to this?Delegation
@MikeOttink Nope. As mentionned in my question, I gave up and used vuex-class-component.Supinate
Also gave up and used vuex-class-component. Works like a charm and has a fraction of the boilerplate.Sulfamerazine
A
5

What your doing in your index.ts file is incorrect if your trying to make your store modules register dynamically.

Define an empty store in store/index.ts

import Vuex from 'vuex'

export const store = new Vuex.Store<any>({});

Now in your store modules:

// store/CommonModule.ts
import { Module, VuexModule, Mutation } from 'vuex-module-decorators'

// import the empty store
import store from '.'

@Module({
  name: 'CommonModule',
  namespaced: true,
  stateFactory: true,

  // add this
  dyamic:true,
  store

})
export default class CommonModule extends VuexModule {
  message: string = 'hi'

  @Mutation
  public SET_MESSAGE(val: string) {
    this.message = val
  }
}

Augustusaugy answered 27/3, 2020 at 13:18 Comment(0)
H
3

Was fighting with a similar problem and got it to work with code from this page: https://qiita.com/yoshinbo/items/70f109db7c3de4b4a99f

  • use the store in your module definition
  • export result of getModule from your module file
  • default export createStore from ~/store/index.ts
Highball answered 29/2, 2020 at 9:11 Comment(2)
Thank you, this helps!Hutcherson
awesome. store.state.moduleName.stateName works as well. and can be used it in the middlewares.Milka
E
1

Well, you need to call the Message() function inside of the created() lifecycle hook.

Currently as per your code, script starts the executing whenever component is Initialise but by that time store has not been in set up due to which calling it inside lifecycle hooks would make more sense.

public created() {
  get message(): string {
    const commonModule = getModule(CommonModule, this.$store)
    return commonModule.message;
  }
}

Hope this helps!

Excogitate answered 28/2, 2020 at 0:43 Comment(2)
Actually, my message function is a getter and it's not valid to declare a getter inside a function (throws error).Supinate
I gave up and moved to vuex-module-class. This one is working for nuxt.Supinate
D
0

For anyone who still wants to use vuex-module-decorator:

From the example of Atlasmaybe's question, it was missing a store-accessor.ts file: check the docs

We have to make some adjustments in the existing files, and we'll be using the getModule function in this new one:

1 - First in our custom module:

// store/CommonModule.ts
import { Module, VuexModule, Mutation } from 'vuex-module-decorators'

@Module({
  // change the name to lower case
  name: 'commonmodule',
  namespaced: true,
  stateFactory: true,
})
// no need to name the class:
export default class extends VuexModule {
  message: string = 'hi'

  @Mutation
  public SET_MESSAGE(val: string) {
    this.message = val
  }
}

2 - Then create a store-accessor.ts file, inside a utils folder:

// utils/store-accessor.ts
import { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import commonmodule from '~/store/CommonModule'

// this is the name we'll use to import the module
let commonModuleStore: commonmodule

function initialiseStores(store: Store<any>): void {
  commonModuleStore = getModule(commonmodule, store)
}

export { initialiseStores, commonModuleStore }

3 - Now at your store index.ts:

// store/index.ts
import { Store } from 'vuex';
import { initialiseStores } from '~/utils/store-accessor';

const initializer = (store: Store<any>) => initialiseStores(store);

export const plugins = [initializer];

export * from '~/utils/store-accessor';

4 - And finally at our component, we can import the custom store and use it like:

// components/Home.vue
import { Component, Vue } from 'vue-property-decorator';

// import goes from:
// import CommonModule from '~/store/CommonModule';
// to:
import { commonModuleStore } from '~/store';

@Component
export default class Home extends Vue {
    get message(): string {
        // usage:
        commonModuleStore.SET_MESSAGE('hello world');
        console.log(commonModuleStore.message); // hello world
    }
}
Dilly answered 27/10, 2021 at 19:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.