Search code examples
javascriptsortingvue.jsvuexmutation

How to sort data in Vuex state with mutation


I have an array of objects that displays in a table on my html page in one of my Vue components. The array of objects is data in the state of a Vuex store.

export const store = new Vuex.Store({
    state: {
        jobs: [{...},{...},{...},{...},{...},{...}]
    },
    mutations: {
        sortJobs(state, sortKey) {
            console.log('running mutation');
            let compare = 0;
            this.state.jobs.sort((a, b) => {
                if (a.sortKey > b.sortKey) {
                    compare = 1;
                } else if (b.sortKey > a.sortKey) {
                    compare = -1;
                }
                return compare;
            });
        }
    },
    getters: {
        jobs: state => state.jobs
    }
});

I am trying to sort the array of objects in the mutation sortJobs, but it will not work. I am calling the mutation in one of my components.

methods: {
    sortBy: function(sortKey) {
        this.$store.commit('sortJobs', sortKey);
    }
}

This will not change the order of the array of objects, nor in my table. I've tested to see if I can do anything to the array of objects, and when I replace this.state.jobs.sort(...) with this.state.jobs.shift();, the first object element in the array disappears off of my table. But when it comes to sorting, I can't get this to sort at all. What am I doing wrong?


Solution

  • Arrays are tricky in Vue. Take a look at these common gotchas.

    Instead of mutating the array in place, try making a copy, sorting the copy and setting state.jobs to that sorted array.

    Something like this:

      mutations: {
        sortJobs(state, sortKey) {
            console.log('running mutation');
            const jobs = this.state.jobs;
            jobs.sort((a, b) => {
                let compare = 0;
                if (a[sortKey] > b[sortKey]) {
                    compare = 1;
                } else if (b[sortKey] > a[sortKey]) {
                    compare = -1;
                }
                return compare;
            });
            state.jobs = jobs;
        }
      },
    

    Also:

    • move the instantiation of the compare variable into the sort callback, so it'll be new each time you sort two list items.
    • instead of using a.sortKey, which will literally look for the sortKey property, use a[sortKey], which will let you access a variable attribute.

    Working example, without vuex: https://jsfiddle.net/ebbishop/7eku4vf0/