7

In almost all guides, tutorial, posts, etc that I have seen on vuex module registration, if the module is registered by the component the createNamespacedHelpers are imported and defined prior to the export default component statement, e.g.:

import {createNamespacedHelpers} from 'vuex'
const {mapState} = createNamespacedHelpers('mymod')

import module from '@/store/modules/mymod'

export default {
  beforeCreated() {
    this.$store.registerModule('mymod', module)
  }
}

this works as expected, but what if we want the module to have a unique or user defined namespace?

import {createNamespacedHelpers} from 'vuex'
import module from '@/store/modules/mymod'

export default {
  props: { namespace: 'mymod' },
  beforeCreated() {
    const ns = this.$options.propData.namespace
    this.$store.registerModule(ns, module)
    const {mapState} = createNamespacedHelpers(ns)
    this.$options.computed = {
      ...mapState(['testVar'])
    }
  }
}

I thought this would work, but it doesnt.

Why is something like this needed? because

export default {
  ...
  computed: {
    ...mapState(this.namespace, ['testVar']), 
    ...
  },
  ...
}

doesnt work

SumNeuron
  • 4,850
  • 5
  • 39
  • 107
  • Was facing similar problem, trying to access dynamic namespace items from the store and I found another workaround: Instead of non-working `computed: { ...mapState(this.namespace, ['testVar']), }`, I use: `computed: { testVar(){ return this.$store.state[this.namespace].testVar; } }` – John Overiron Mar 21 '19 at 12:41

3 Answers3

3

This style of work around by utilising beforeCreate to access the variables you want should work, I did this from the props passed into your component instance:

import { createNamespacedHelpers } from "vuex";
import module from '@/store/modules/mymod';

export default {
  name: "someComponent",
  props: ['namespace'],
  beforeCreate() { 
    let namespace = this.$options.propsData.namespace;
    const { mapActions, mapState } = createNamespacedHelpers(namespace);

    // register your module first
    this.$store.registerModule(namespace, module);

    // now that createNamespacedHelpers can use props we can now use neater mapping
    this.$options.computed = {
      ...mapState({
        name: state => state.name,
        description: state => state.description
      }),

      // because we use spread operator above we can still add component specifics
      aFunctionComputed(){ return this.name + "functions";},
      anArrowComputed: () => `${this.name}arrows`,
    };

    // set up your method bindings via the $options variable
    this.$options.methods = {
      ...mapActions(["initialiseModuleData"])
    };
  },

  created() {
    // call your actions passing your payloads in the first param if you need
    this.initialiseModuleData({ id: 123, name: "Tom" });
  }
}

I personally use a helper function in the module I'm importing to get a namespace, so if I hadmy module storing projects and passed a projectId of 123 to my component/page using router and/or props it would look like this:

import projectModule from '@/store/project.module';

export default{
  props['projectId'], // eg. 123
  ...
  beforeCreate() {
    // dynamic namespace built using whatever module you want:
   let namespace = projectModule.buildNamespace(this.$options.propsData.projectId); // 'project:123'

   // ... everything else as above
  }
}

Hope you find this useful.

Tom 'Blue' Piddock
  • 2,131
  • 1
  • 21
  • 36
2

All posted answers are just workarounds leading to a code that feels verbose and way away from standard code people are used to when dealing with stores.

So I just wanted to let everyone know that brophdawg11 (one of the commenters on the issue #863) created (and open sourced) set of mapInstanceXXX helpers aiming to solve this issue.

There is also series of 3 blog posts explaining reasons behind. Good read...

Michal Levý
  • 33,064
  • 4
  • 68
  • 86
0

I found this from veux github issue, it seems to meet your needs https://github.com/vuejs/vuex/issues/863#issuecomment-329510765

{
  props: ['namespace'],

  computed: mapState({
    state (state) {
      return state[this.namespace]
    },
    someGetter (state, getters) {
      return getters[this.namespace + '/someGetter']
    }
  }),

  methods: {
    ...mapActions({
      someAction (dispatch, payload) {
        return dispatch(this.namespace + '/someAction', payload)
      }
    }),
    ...mapMutations({
      someMutation (commit, payload) {
        return commit(this.namespace + '/someMutation', payload)
      })
    })
  }
}

... or maybe we don't need mapXXX helpers, mentioned by this comment https://github.com/vuejs/vuex/issues/863#issuecomment-439039257

computed: {
    state () {
      return this.$store.state[this.namespace]
    },
    someGetter () {
      return this.$store.getters[this.namespace + '/someGetter']
    }
  },
ianYa
  • 19
  • 4