vuex-class-component icon indicating copy to clipboard operation
vuex-class-component copied to clipboard

Example on how to use with Nuxt

Open SandroMaglione opened this issue 4 years ago • 3 comments

I am trying to make the library work with Nuxt.

The docs say that what you need is:

export class UserStore extends createModule({ target: "nuxt" }) {
  ...
}

To test it, I created a new file in the store folder of my Nuxt project. The file contains the class of the example in the docs:

import { createModule, mutation, action } from 'vuex-class-component'

export class UserStore extends createModule({
  strict: false,
  target: 'nuxt'
}) {
  firstname = 'Michael'
  lastname = 'Olofinjana'
  specialty = 'JavaScript'

  @mutation clearName() {
    this.firstname = ''
    this.lastname = ''
  }

  @action async doSomethingAsync() {
    const val1 = await new Promise(() => this.firstname)
    return val1
  }

  @action async doAnotherAsyncStuff(payload: { func: Function }) {
    const number = await this.doSomethingAsync()
    payload.func()
    return payload + this.fullname + number
  }

  // Explicitly define a vuex getter using class getters.
  get fullname() {
    return this.lastname + this.firstname
  }

  // Define a mutation for the vuex getter.
  // NOTE this only works for getters.
  set fullname(name: string) {
    const names = name.split(' ')
    this.firstname = names[0]
    this.lastname = names[1]
  }

  get bio() {
    return `Name: Specialty: ${this.specialty}`
  }
}

I would expect this code to create a new module with the name of the file and relative state (firstname, lastname, specialty), and the getters defined by the class, as well as actions and mutations.

The code compiles, but then the store seems to be empty (from Vuejs devtool): user: Object (empty), and getter are not present at all.

How can I make it work? Am I missing something?

SandroMaglione avatar Nov 06 '20 10:11 SandroMaglione

I think the problem with your code above is here:

export class UserStore extends createModule({ strict: false, target: 'nuxt' }) { ...

Instead it should be like this:

const VuexModule = createModule({
  namespaced: "main",
  strict: false,
  target: "nuxt",
})

export class MainStore extends VuexModule {
   ...

You need to namespace the store.

swetjen avatar Dec 02 '20 19:12 swetjen

See for a fully working example: https://github.com/TAC/nuxt-vuex-typescript-example/blob/master/app/src/store/modules/counter.ts

michael-scheurer avatar Jan 26 '22 23:01 michael-scheurer

Little update, there is a new version of the library. This is my solution, feel free to comment :)

store/user.ts

import { action, createModule, getter, mutation } from 'vuex-class-component'
import { extractVuexModule } from 'vuex-class-component/dist/module'

export class User extends createModule({
  target: 'nuxt',
  enableLocalWatchers: true,
}) {
  private firstname = 'Michael'
  private lastname = 'Olofinjana'
  @getter speciality = 'JavaScript' // The @getter decorator automatically exposes a defined state as a getter.
  @getter occupation = 'Developer'

  static $watch = {
    speciality: (newValue: string) =>
      console.log(`Fullname has changed ${newValue}`),
  }

  static $subscribeAction = {
    doSomethingAsync() {
      console.log(`fetchDetails action was called with payload`)
    },
  }

  @mutation changeName({
    firstname,
    lastname,
  }: {
    firstname: string
    lastname: string
  }) {
    this.firstname = firstname
    this.lastname = lastname
  }

  @action doSomethingAsync() {
    this.speciality = this.$store.app.$vxm.user.firstname
    return Promise.resolve('20')
  }

  @action async doAnotherAsyncStuff(payload: string) {
    const number = await this.doSomethingAsync()
    console.log(number)
    this.changeName({ firstname: 'John', lastname: 'Doe' })
    return payload + this.fullName
  }

  // Explicitly define a vuex getter using class getters.
  get fullName() {
    return this.firstname + ' ' + this.lastname
  }
}

export default Object.values(extractVuexModule(User))[0]

Vue Chrome plugin

Capture d’écran 2022-05-02 à 11 29 41

Accessor Plugin plugins/store.ts

import { Plugin } from '@nuxt/types'
import { createProxy } from 'vuex-class-component'
import { User } from '~/store/user'
import { Car } from '~/store/car'

const createVxm = (store: any) => ({
  user: createProxy(store, User),
  car: createProxy(store, Car),
})

type vxmType = ReturnType<typeof createVxm>

declare module 'vue/types/vue' {
  interface Vue {
    $vxm: vxmType
  }
}

declare module '@nuxt/types' {
  interface NuxtAppOptions {
    $vxm: vxmType
  }
  interface Context {
    $vxm: vxmType
  }
}

const storePlugin: Plugin = ({ store }, inject) => {
  inject('vxm', createVxm(store))
}

export default storePlugin

moifort avatar May 02 '22 10:05 moifort