Reputation: 2796
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>
Upvotes: 1
Views: 250
Reputation: 23473
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']
)
}
}
Upvotes: 2
Reputation: 1388
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 :)
Upvotes: 0