Reacting to router param change.



  • I have a router entry with

    {path: 'strategy/net/:id', component: () => import('../')},
                {path: 'strategy/manual/:id', component: () => import('../')},
    

    and component pointing to it with

    <q-item clickable v-ripple :inset-level="level/2" :to="router" exact>
    

    where router is variable with entries such as

    /strategy/net/foo1
    /strategy/manual/foo2
    /strategy/manual/bar1
    

    Component is common for all pages (it’s navigation bar)
    If i click on foo2 I go to foo2 page, however I can’t go to bar1 from foo2. The url in browser location bar changes, but component is not updated. I can get to bar1 from foo1 page.
    I looked into vue manual and found this page: https://router.vuejs.org/guide/essentials/dynamic-matching.html#reacting-to-params-changes
    Looks like it describes my issue precisely.
    I use composition api and can’t figure out how can I force component to re-run setup() section and fetch data for new id. If would be nice if this behavior can be completely disabled somehow.



  • @kernelconf

    You could use a watch in the setup:

    setup() {
       const article = reactive({...});
       function fetchArticle(id) {
          //assign article..
       }
       watch('$route.params.articleId', fetchArticle)
       return { article };
    }
    

    Here is the article with some more solutions:
    https://medium.com/js-dojo/watch-vue-route-params-query-with-composition-api-97b3c8c402e

    (if you can’t read it because medium wants you to register or pay 5$ , try to view it in an incognito chrome window):



  • This method doesn’t work if you are using typescript - you can’t pass a string as the first parameter to watch.

    I also tried the method where you create a hook like this and it’s not working either:

    // router.js
    const route = Vue.observable<Route>({
      fullPath: '',
      hash: '',
      matched: [],
      params: {},
      path: '',
      query: {},
    });
    
    Router.afterEach((to) => {
      Object.assign(route, to);
      console.log({route}) // this console log always executes
    });
    
    export const useRoute = () => computed(() => route);
    
    // in the component
    setup() {
      const route = useRoute();
      watch(route, (newVal) => console.log(newVal)); //this console log never executes
    }
    

    It’s weird because the console.log in the afterEach hook always runs but the one in the watcher never does…



  • I found out why it wasn’t working for me - when the Object.assign() call is made it only modifies the properties and not the entire object so the computed function is not actually triggered to rerun.

    This example works for my use case (hope it helps someone else 😄 )

    const routerState = Vue.observable<{route: Route}>({
      route: {
        fullPath: '',
        hash: '',
        matched: [],
        params: {},
        path: '',
        query: {},
      },
    });
    
    Router.afterEach((to) => {
      Object.assign(routerState, { route: to });
    });
    
    export const useRoute = () => computed(() => routerState.route);
    


  • Thanks for help, I use ts, so I’ve altered @dobbel snipped to

                watch(() => context.root.$route.params.id, (first, second) => {
                    strategyCode.value = first
                });
    

    Component uses a new id without any other coding, amazing.


Log in to reply