Search code examples
vue.jsvue-componentvuexvue-router

Page header component - Can’t get Vuex to update store on nested child component


I have a Vue app where I have created a Page Header component which is pulled into the high level view components (Home, Library, Classroom). In each of these ‘higher’ level views I have a router-view where nested ‘children route’ components get loaded. I wanted to change the heading in the Page Header component to match whatever component gets loaded. Naturally after doing some research I saw that I could not use props or slots to get the functionality I needed. I do know I can use route params or queries to get the job done, however I don’t want that extra info cluttering the url.

I decided to use Vuex to store the data needed for Page Header component, as it would be centralized data I could access from anywhere. For my solution I used called a mutation on the created() hook of a component to update the Page Title store data when one of the pages load. However, this works great on the initial load, but this only fires once (created()). If I navigate back to a page, the title does not update.

In order to make this work do I need to watch the ‘$route’ for changes? Any help would be appreciated. I can not figure out how to recommit a mutation on a route change.

Code below:

page-header.vue

    <template>
        <div class="page-header">

           <h2>{{ getPageTitle }}</h2>

        </div>
    </template>

    <script>

        export default {
            name: 'pageHeader',
            computed: {
                getPageTitle(){
                    return this.$store.state.pageTitle;
                }
            }
        }

    </script>

store/store.js

    export const store = new Vuex.Store ({
        state: {
            pageTitle: '',
        },
        mutations: {
            setPageTitle(state, payload) {
                state.pageTitle = payload.pageTitle;
            }
        }

    });

Library.vue

    <template>

      <div>

        <page-header />

          <router-view></router-view>

      </div>

    </template> ....

library-feed.vue (default child route to Library.vue, that populates router-view )

    <template>
    ...
    </template>

    <script>

        export default {
        name: 'libraryFeed',
        created() {
            this.$store.commit('setPageTitle', {pageTitle: 'Library'})
        },
    }

    </script>

Solution

  • Thanks @moritzgvt. I saw that it was working perfectly on your demo. I suspected that it could have been the nested child routes, but I edited your codesandbox and that also worked.

    Due to this I went back and looked and realised that I had keep-alive tags around my main router-view in my App.vue ....

    I found out here (How to use keep-alive in vuejs?) that using keep alive tags like this:

        <keep-alive>
    
           <router-view></router-view>
    
        </keep-alive>
    

    Is that it keeps the router view in memory and the state as well as the lifecycle hooks like created() and mounted() are not reset.

    So removing the tags solved it!