Vuex getters

Published 1 year ago by TheFriendlyHacker

Is it possible to pass extra arguments to Vuex getters?

For example, I want to make a getter that can grab an object from an array based on it's id:

const state = [
    {id: 1, name: "John"},
    {id: 2, name: "Doe"},
    {id: 3, name: "Jane"}
];

const getters = {
    // The "theoretical" getter I want, which accepts an id as a second argument
    byId: (state, id) => state.find( (item) => item.id === id ) 
};

But I can't find anywhere in the Vuex documentation that states anything about passing extra arguments to a getter when calling it from a Vue component (it mention that you can pass another getter in as an argument...but that's not what I want).

Is it even possible to do what I am looking for? And if not, how should I go about retrieving items from my state based on dynamic attributes?

Best Answer (As Selected By TheFriendlyHacker)
erikgall

I'm 99% sure that you can't. There are a couple ways around this depending on what you're doing.

If you have an array of items and you use one item at a time and you need to get/store the current/active item.

const state = {
    items: [],
    current: null
}

const mutations = {

    [SET_CURRENT](state, item) {
        state.item = item
    },
    
    [SET_CURRENT_BY_ID](state, id) {
        state.current = state.items.find((item) => item.id == id)
    }
}

const getters = {
    items: (state) => state.items,  
    currentItem: (state) => state.current,
}

If you want to get an item on the fly based on a dynamic attribute, you have to use a computed property:

computed: {
    current() {
        return this.$store.getters.items.find((item) => item.id == this.current)
    }
},
data() {
    return {
        current: 0
    }
}
erikgall

I'm 99% sure that you can't. There are a couple ways around this depending on what you're doing.

If you have an array of items and you use one item at a time and you need to get/store the current/active item.

const state = {
    items: [],
    current: null
}

const mutations = {

    [SET_CURRENT](state, item) {
        state.item = item
    },
    
    [SET_CURRENT_BY_ID](state, id) {
        state.current = state.items.find((item) => item.id == id)
    }
}

const getters = {
    items: (state) => state.items,  
    currentItem: (state) => state.current,
}

If you want to get an item on the fly based on a dynamic attribute, you have to use a computed property:

computed: {
    current() {
        return this.$store.getters.items.find((item) => item.id == this.current)
    }
},
data() {
    return {
        current: 0
    }
}
TheFriendlyHacker

Thanks! That makes sense

tomwilsonfl

From the documentation at https://vuex.vuejs.org/en/getters.html:

You can also pass arguments to getters by returning a function. This is particularly useful when you want to query an array in the store:

getters: {
  // ...
  getTodoById: (state, getters) => (id) => {
    return getters.todos.find(todo => todo.id === id)
  }
}

store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

And here is how I use it in one of my components. I call my "getTodoById" simply "find":

In my store module:

getters: {
        find: (state, getters) => (id) => {
            return getters.all.find(obj => obj.id == id);
        },
        
        all: (state) => { return state.data }
    },
    

In my component:

computed: {
        ...mapGetters('registrations', { getRegistration: 'find' }),
        
        registration: function () {
            return this.getRegistration(this.$route.params.id);
        }
    },

Don't forget to import "mapGetters" in your component. That held me up at first:

import { mapGetters } from 'vuex';

Hope this helps.

alexsasharegan

So @tomwilsonfl has the right idea on returning a function to "pass extra parameters" to a getter. I wanted to share another idea that harkens back to good ol' Backbone.js collections—compute an object that indexes your array of objects by id. Like so:


const store = new Vue.Store({
    state: {
        items: [
            {id: 1, name: "John"},
            {id: 2, name: "Doe"},
            {id: 3, name: "Jane"}
        ]
    },
    getters: {
        itemsById({ items }, getters) {
            return items.reduce(
                (memo, item) => Object.assign(memo, { [item.id]: item })
                , {}
            )
        },
    }
})

const app = new Vue({
    el: '#app',
    store
})

app.$store.getters.itemsById[3]
// {id: 3, name: "Jane"}
hootlex
hootlex
1 year ago (28,075 XP)

It is possible to pass arguments to Vuex getters by returning a function.

Doc's example:

getters: {
  // ...
  getTodoById: (state, getters) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}

Please sign in or create an account to participate in this conversation.