UP | HOME
Diego Rodriguez Mancini

Diego Rodriguez Mancini

Software Engineer

Vuex Module Communication Using Nuxt with Nuxt Property Decorators
Published on Aug 01, 2020 by Diego Rodriguez Mancini.

Introduction

When working with nuxt-property-decorators or specifically vuex-module-decorators I found that It was not clear how to make it work with Nuxt.

One thing that I could not figure out was how to call actions or mutations from inside modules. In this example I did a simple flow:

`Component -> first module -> second module -> first module`

First Module

The idea is that the component will get data from this module’s state. And this module sets the data through a different module.

import {
  Module,
  VuexModule,
  VuexMutation,
  VuexAction,
} from 'nuxt-property-decorator'
import { second } from '~/store'
@Module({
  name: 'first',
  namespaced: true,
  stateFactory: true,
})
export default class First extends VuexModule {
  text = 'before update'

  @VuexMutation
  setText(val) {
    this.text = val
  }

  @VuexAction({ rawError: true })
  setTextSecond(val) {
    second.setText(val)
  }
}

You can also dispatch an action from inside a module using namespaces. To do so, add a third parameter to the dispatch function with `{ root: true }`

@VuexAction({ rawError: true })
setTextSecond(val) {
  this.context.dispatch('second/setText', val, { root: true })
}

Note that I added an argument to VuexAction decorator. With `{ rawError: true }` I get the real error if something goes wrong inside my action function. Otherwise it will throw a generic error that can be confusing.

Second Module

This module will set the first module’s state by calling the mutation on that module.

import { Module, VuexModule, VuexAction } from 'nuxt-property-decorator'
import { first } from '~/store'
@Module({
  name: 'second',
  namespaced: true,
  stateFactory: true,
})
export default class second extends VuexModule {
  @VuexAction({ rawError: true })
  setText(val) {
    first.setText(val)
  }
} 

Component

It works importing the stores or by using the namespace

Using namespace

<template>
  <v-container>
    <div>text is: {{ text }}</div>
  </v-container>
</template>

<script>
import { Vue, Component } from 'nuxt-property-decorator'
@Component
export default class StoreTestComponent extends Vue {
  beforeMount() {
    this.$store.dispatch('first/setTextSecond', 'after update')
  }

  get text() {
    return this.$store.state.first.text
  }
}
</script>

Using Module as Class

<template>
  <v-container>
    <div>text is: {{ text }}</div>
  </v-container>
</template>

<script>
import { Vue, Component } from 'nuxt-property-decorator'
import { first } from '~/store'
import { second } from '~/store'
@Component
export default class StoreTestComponent extends Vue {
  beforeMount() {
    first.setTextSecond('after update')
  }

  get text() {
    return first.text
  }
}
</script>

Important note: Remember that you have to export the modules in store-accessor.js to make this method work.

// ~/utils/store-accessor.js

import { getModule } from 'nuxt-property-decorator'
import First from '~/store/first'
import Second from '~/store/second'

let first = null
let second = null

function initialiseStores(store) {
  first = getModule(First, store)
  second = getModule(Second, store)
}

export {
  initialiseStores,
  first,
  second,
}
// ~/store/index.js

import { initialiseStores } from '~/utils/store-accessor'
const initializer = (store) => initialiseStores(store)
export const plugins = [initializer]
export * from '~/utils/store-accessor'