Dejavu
Dejavu

Reputation: 713

Vuex mapState based on route and route parameters

I have a works component I use different pages on my app and I am trying to load the state based on the route and route parameters.

In my App.vue file I dispatch the async action to get the json file like

mounted() {
    this.$store.dispatch('getData')
},

And I map the state in my works component like that

export default {
    name: 'Works',
    computed: mapState({
        works: (state) => state.works.home.items.slice(0, state.works.home.loadedCount),
        loadedCount: (state) => state.works.home.loadedCount,
        totalCount: (state) => state.works.home.items.length,
    })
}

I actually need to map the state dynamically based on the route just like state.works[this.$router.currentRoute.params.category] or based on route name. Could you please tell me what is the correct way to get the data (async) from my state?

Vuex store:

export default new Vuex.Store({
    state: {
        works: {
            all: {
                items: [],
                loadedCount: 0,
            },
            home: {
                items: [],
                loadedCount: 0,
            },
            web: {
                items: [],
                loadedCount: 0,
            },
            print: {
                items: [],
                loadedCount: 0,
            },
        },
        limit: 2,
    },
    mutations: {
        SET_WORKS(state, works) {
            state.works.all.items = works
            works.map((el) => {
                if (typeof state.works[el.category] !== 'undefined') {
                    state.works[el.category].items.push(el)
                }
            })
        },
    },
    actions: {
        getData({ commit }) {
            axios
                .get('/works.json')
                .then((response) => {
                    commit('SET_WORKS', response.data.works)
                })
        },
    },
})

Upvotes: 3

Views: 681

Answers (1)

Igor Moraru
Igor Moraru

Reputation: 7729

You can do it in beforeCreate hook.

beforeCreate(){
    const category = this.$route.params.category;

    Object.assign(this.$options.computed, {
      ...mapState({
        categoryItems: (state) => state.categories[category],
      }),
    });
}

I've created a basic working example: https://codepen.io/bgtor/pen/OJbOxKo?editors=1111

UPDATE:

To get mapped properties updated with route change, you will have to force re-render the component. The best way to do it, is to change the component key when route change in parent component.

Parent.vue

<template>
  <categoryComponent :key="key"></categoryComponent> // <-- This is the component you work with
</template>

computed: {
  key(){
     return this.$route.params.category
  }
}

With this approach the beforeCreate hook will be triggered with every route change, getting fresh data from Vuex.

Upvotes: 2

Related Questions