1

I'd like to create a component that I can instantiate multiple times pointing at (loading its data from) different vuex-namespaces. The component will gets most of its data from Vuex. So say I have a Person component, I could instantiate many copies of the Person component, based on different paths into vuex.

The best way I've figured out how to do this is to pass a vuex path as a prop, but then I don't know how to use mapGetters and friends, because they require a namespace at the time the .vue file is instantiated.

I'd appreciate insight into the best "Vue way" to structure this. Here's the closest approach I've figured out at the moment.

Person.vue:

<template>
    <div>person {{name}} is {{age}} years old</div>
</template>

<script>
  export default {
    props: ['vuexNamespaceToLoadFrom'],

    // FIXME: how do I do a mapGetters with a dynamic namespace that's 
    // set through props???

    // I can't do the following since props aren't in scope yet :-(
    ...mapGetters(this.vuexNamespaceToLoadFrom, [ 'name', 'age'])

  }
</script>

Instantiating a few Person multiple-use components that load their properties from different vuex-namespaces:

<Person vuex-namespace-to-load-from="api/jim">
<Person vuex-namespace-to-load-from="api/someotherpath/rachid">
<div>
 <Person vuex-namespace-to-load-from="api/alternatepeople/grace">
</div>

2 Answers 2

2

To expand the problem definition a little, this

export default {
  props: ['vuexNamespaceToLoadFrom'],
  ...
  computed: {
    ...mapGetters(this.vuexNamespaceToLoadFrom, [ 'name', 'age'])
  }
}

is a declarative object used by Vue to create instances of components, so instance properties can't be used directly in the helpers like mapGetters.

However, this discussion Generating computed properties on the fly shows a way to defer the evaluation of the instance property.

Essentially, the body of the computed get() will not be evaluated until the instance is fully mounted, so references to this.$store and this[namespaceProp] will work here.

Adapting it to your scenario,

helper function

function mapWithRuntimeNamespace({namespaceProp} = {}, props = []) {
  return props.reduce((obj, prop) => {
    const computedProp = {
      get() {
        return this.$store.getters[this[namespaceProp] + '/' + prop]
      }
    }
    obj[prop] = computedProp
    return obj
  }, {})
}

usage

export default {
  props: ['vuexNamespaceToLoadFrom'],
  ...
  computed: {
    ...mapWithRuntimeNamespace(
      { namespaceProp: 'vuexNamespaceToLoadFrom' }, 
      ['name', 'age']
    )
  }
}
Sign up to request clarification or add additional context in comments.

Comments

0

How about this?

Person component:

export default (vuexNamespace) => ({
  ...mapGetters(vuexNamespace, ['name', 'age']) 
})

Parent component:

export default {
  components: {
    Person: Person('someNamespace')
  }
}

Didn't test it out, but I think it should work :)

2 Comments

I like the thinking, but it doesn't work for vue-loader
Seems like they didn't consider this kind of usage :) Well, I don't have any other ideas for now, sorry :(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.