Jackson J
Jackson J

Reputation: 1523

Reactive getter in vuex?

I have getter in vuex which returns item from list

const store = new Vuex.Store({
    state: { arr: {
        1: {name: 'one', attr: true},
        2: {name: 'two', attr: false} 
    },
    mutations: {
        setArrItemName(state, id, name) {
            Vue.set(state.arr, id, name);
        }
    },
    getters: {
        arrItemById(state, getters) => (id) => {
            const item = state.arr[id];
            if(item) return item;
            return {
                 name: 'default', attr: true
            };
        }
    }
})

If I output it in template

{{ $store.state.arr[1]['name'] }}

it updates fine when another part calls

this.$store.commit('setArrItemName', 1, 'new name');

But if template contains

{{ $store.getters.arrItemById(1).name }}

Then it's not updated

Problem: this getter is used in different places and I do not want to duplicate this code

<template v-if='$store.state.arr[id]'>
    {{ $store.state.arr[id].name }}
</template>
    Default
<template v-else>
</template>

If 'default' some day changes, or any other attribute of default object then it should be updated in different places.

Upvotes: 11

Views: 27609

Answers (3)

Vamsi Krishna
Vamsi Krishna

Reputation: 31362

Try using computed properties for accessing your getters. First, import the mapGetters function from Vuex:

import {mapGetters} from 'vuex';

Then, add computed properties for the getters you want as follows:

computed: {
    ...mapGetters({
        getterName: 'your-getter-name-in-store'
    })
} 

We use a spread operater ( ... ) while using the mapGetters helper; you can read more about why here.

Then, in your template, use {{ getterName }}.

This also overcomes your problem of code duplication, as you won't need to use this.$store.getters everywhere.

Upvotes: 9

Richard Matsen
Richard Matsen

Reputation: 23473

I don't know if this typo is just in the question, or in your program too...

from above

const store = new Vuex.Store({
    state: { arr: {
        1: {name: 'one', attr: true},
        2: {name: 'two', attr: false} 
    },
    mutations: {
       ...

should be

const store = new Vuex.Store({
    state: { arr: {
        1: {name: 'one', attr: true},
        2: {name: 'two', attr: false} 
      } // missing this closing brace on object arr
    },
    mutations: {
       ...

That might explain the getter problem.

Upvotes: 0

Tobino
Tobino

Reputation: 942

You can't get reactive on getter which is not pure. You can create a computed property on local.

Sources : https://github.com/vuejs/vuex/issues/145#issuecomment-230488443

I made some research, and you can use computed function with a getter inside :

  computed: {
    arr() {
            return this.$store.getters.arrItemById(this.id);
      }
  },

Here is a jsfiddle example.

Upvotes: 3

Related Questions