michaelolof / vuex-class-component

A Type Safe Vuex Module or Store Using ES6 Classes and ES7 Decorators written in TypeScript.
217 stars 21 forks source link

Can't access store instance from @action #22

Closed zourtney closed 5 years ago

zourtney commented 5 years ago

Is there a way to access the store instance from within an @action method? Using vanilla Vuex, this refers to the store instance.

Specifically, I'm trying to do this to access store.$axios, which Nuxt decorates onto the store instance:

actions: {
  async fetch() {
    // `this` is Vuex Store instance
    // `this.$axios` is defined.
  }
}

I tried using @action({ mode: 'raw' }) and getRawActionContext(this), but the resulting context is the same. And skimming through the source, it looks like the $store instance from the createProxy call is never persisted.

@action({ mode: 'raw' })
async fetch() {
  const context = getRawActionContext(this);
  // context === this
  // this.$axios is not defined.
}

Do you have any suggestions? My current workaround is to pass it into the @action handler from the calling component. But, this shouldn't be necessary, as I can access this.$axios from action handlers defined in vanilla Vuex.

asmadsen commented 5 years ago

@zourtney I have created a pull request with some changes that might work. However I suspect it is a Nuxt specific feature and not related to Vuex. You can try it for yourself by running npm i asmadsen/vuex-class-component and let me know if it works or not.

zourtney commented 5 years ago

Thanks @asmadsen! I did a quick test, and it looks like this does address my issue. I'll be experimenting more with it today...

Yihao-G commented 5 years ago

When I try to dispatch a mutate action inside another action, this.$store is undefined. Just wondering, is that expected?

michaelolof commented 5 years ago

dispatch doesn't work with mutate actions you call them directly.

To call dispatch, use the context object via getRawActionContext function

Yihao-G commented 5 years ago

@michaelolof Thank you for your reply. Sorry, my fault, after testing it again, this.$store is not undefined.

However, in some cases, this.$store is an ActionContext not Store, and thus no access to $axios. This happens after a proxy is created in a middleware by using CreateProxy, and at another location (could be another middleware or a component) a proxy is created again later.

Sample project: https://codesandbox.io/s/vqk4b

rodrigost23 commented 4 years ago

I still have this issue: this.$store exists, but this.$store.$axios doesn't.

import { createModule, action } from 'vuex-class-component'
import Item from '~/models/Item'

export class ApiStore extends createModule({
  strict: false,
  target: 'nuxt',
}) {
  auth = false
  items: Item[] = []

  @action({ mode: 'mutate' }) async getItems() {
    console.log(this.$store.$axios) // <-- undefined
  }
}

I'm using createProxy in a nuxt plugin:

const storeProxies: Plugin = (context, inject) => {
  inject('api', createProxy(context.store, ApiStore))
}

And then using it inside a component:

this.$api.getItems()

EDIT: As a workaround, I've added the axios instance to the store in the plugin:

const storeProxies: Plugin = (context, inject) => {
  const api = createProxy(context.store, ApiStore)
  api.axios = context.$axios
  inject('api', api)
}
ZeroThe2nd commented 2 years ago

I'm actually still running into this issue. Nuxt it's $axios instance is type hinted under this.$store.$axios and this.$store.app.$axios, but neither give me access to the Axios instance. Both are undefined.