VueJs + Vite + VueRouter: Can't get current route in setup() (despite many tutorials showing how to do it)

417 views Asked by At

I have a vite (4.4.5) / vue (3.3.4) / vue-router (4.2.5) problem. I try to detect which child-page is currently active based on my vue router.

There's plenty of tutorials and stackoverflow posts (like here) that answer just that. Unfortunately, after trying about 30 different ways, I am still stuck: Whatever I try, I always get "undefined" when trying to detect in the "setup()" which route I am on.

Even more strangely, when I just put {{ $router.currentRoute }} into the html body, I do see a json with the route inside.

As an example, I used this approach which seems to do the trick for lots of people (other stackoverflow threads & other websites suggest pretty much all the same approach).

With the following code (based on above approach), I get no response in the console, nor on the UI for the parts calculated in setup(). I have annotated in the code the respective answers (or lack thereof).

I'm at the end of my wits and would appreciate any pointers.

Thank you all for your time.

<!-- testpage6.vue -->
<script lang="ts">
import { defineComponent, computed, watch } from 'vue';
import { useRoute } from 'vue-router';

export default defineComponent({
  name: 'MyCoolComponent',
  setup() {
    const route = useRoute();  
    console.log('This passes'); // Shows 'This passes' in console
    console.debug('current route name on component setup init: ${route.name}'); // Does not show up in console
    watch(() => route.name, () => {
      console.debug('MyCoolComponent - watch route.name changed to ${route.name}'); // Does not show up in console
    });   
    return { route };
  },
});
</script>

<template>
  <p>Current route name v1: {{ route.name }}</p> <!--  SHOWS NOTHING -->
  <p>Current route name v2: {{ $router.currentRoute }}</p> <!--  SHOWS A JSON -->
</template>

routes.js:

import { createRouter, createWebHistory } from 'vue-router'

import main     from '../layouts/MainLayout.vue'
import search   from '../pages/search.vue'
import download from '../pages/download.vue'
import history  from '../pages/history.vue'
import test1    from '../pages/testpage1.vue'
import test2    from '../pages/testpage2.vue'
import test3    from '../pages/testpage3.vue'
import test4    from '../pages/testpage4.vue'
import test5    from '../pages/testpage5.vue'
import test6    from '../pages/testpage6.vue'

const routes = [
  {
    path: '/',

    component: main,

    children: [
      {path: '/', component: search},
      {path: '/search', component: search},
      {path: '/download', component: download},
      {path: '/history', component: history},      
      {path: '/test1', component: test1},
      {path: '/test2', component: test2},
      {path: '/test3', component: test3},
      {path: '/test4', component: test4},
      {path: '/test5', component: test5},
      {path: '/test6', component: test6}
    ]
  }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})
export default router

Here is what the UI shows:

Current route name v1:

Current route name v2: { "fullPath": "/test6", "path": "/test6", "query": {}, "hash": "", "params": {}, "matched": [ { "path": "/", "meta": {}, "props": { "default": false }, "children": [ { "path": "/", "component": { "sockets": {}, "methods": {}, "__hmrId": "3a1c5473", "__file": "/vite-vue-flask-sqlite/src/pages/search.vue" } }, { "path": "/search", "component": { "sockets": {}, "methods": {}, "__hmrId": "3a1c5473", "__file": "/vite-vue-flask-sqlite/src/pages/search.vue" } }, { "path": "/download", "component": { "props": {}, "sockets": {}, "methods": {}, "__hmrId": "3d81c64d", "__file": "/vite-vue-flask-sqlite/src/pages/download.vue" } }, { "path": "/history", "component": { "props": {}, "__hmrId": "5b08ab79", "__file": "/vite-vue-flask-sqlite/src/pages/history.vue" } }, { "path": "/test1", "component": { "props": {}, "__hmrId": "f82ebe6a", "__file": "/vite-vue-flask-sqlite/src/pages/testpage1.vue" } }, { "path": "/test2", "component": { "props": {}, "__hmrId": "2e9fc06a", "__file": "/vite-vue-flask-sqlite/src/pages/testpage2.vue" } }, { "path": "/test3", "component": { "props": {}, "methods": {}, "__hmrId": "8769e246", "__file": "/vite-vue-flask-sqlite/src/pages/testpage3.vue" } }, { "path": "/test4", "component": { "props": {}, "__hmrId": "42d657e3", "__file": "/vite-vue-flask-sqlite/src/pages/testpage4.vue" } }, { "path": "/test5", "component": { "props": {}, "__hmrId": "96d3e88c", "__file": "/vite-vue-flask-sqlite/src/pages/testpage5.vue" } }, { "path": "/test6", "component": { "name": "MyCoolComponent", "__hmrId": "9a8b85d5", "__file": "/vite-vue-flask-sqlite/src/pages/testpage6.vue" } } ], "instances": { "default": { "leftDrawerOpen": true, "link": "test6", "$socket": {} } }, "leaveGuards": { "Set(0)": [] }, "updateGuards": { "Set(0)": [] }, "enterCallbacks": {}, "components": { "default": { "__hmrId": "22686b16", "__file": "/vite-vue-flask-sqlite/src/layouts/MainLayout.vue" } } }, { "path": "/test6", "meta": {}, "props": { "default": false }, "children": [], "instances": { "default": null }, "leaveGuards": { "Set(0)": [] }, "updateGuards": { "Set(0)": [] }, "enterCallbacks": {}, "components": { "default": { "name": "MyCoolComponent", "__hmrId": "9a8b85d5", "__file": "/vite-vue-flask-sqlite/src/pages/testpage6.vue" } } } ], "meta": {}, "href": "/absproxy/3000/test6" }

Update: Based on the feedback, I've added the code not to the child, but to the main component. Then, I still get no valid results, see below:

 <!-- MainLayout.vue -->
 setup () {
    const leftDrawerOpen = ref(false);
    const route = useRoute();  
    
    const path = computed(() =>route.path)
    console.log(path) ; // Shows 'ComputedRefImpl {dep: undefined, __v_isRef: true, __v_isReadonly: true, _dirty: true, _setter: ƒ, …}''
    
    
    console.debug('current route name on component setup init: ${route.path}'); // Does not show up in console
    watch(() => route.path, () => {
      console.debug('MyCoolComponent - watch route.name changed to ${route.path}'); // Does not show up in console
    });   
    return {
      route
    }
  }
1

There are 1 answers

0
Benjamin On

Here is the final solution:

<!-- MainLayout.vue -->
...
<script lang="ts">
import { watch } from 'vue';
import { useRoute } from 'vue-router';

export default {
  setup() {
    const route = useRoute();  
    console.debug(`${route.path}`); // Shows current route, i.e. /test6 when navigating to test6
    watch(() => route.path, () => {
      console.log(`${route.path}`) // Shows changes in router when this code block is in main component
    });   
    return {
      route,
    }
  },
}
</script>

Router.js:

import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/',
    component: () => import('../layouts/MainLayout.vue'),
    redirect: '/search',

    children: [
      {path: '/search',   component: () => import('../pages/search.vue'), name: 'search'},
      {path: '/download', component: () => import('../pages/download.vue'), name: 'download'},
      {path: '/history',  component: () => import('../pages/history.vue'), name: 'history'},      
      {path: '/test1',    component: () => import('../pages/testpage1.vue'), name: 'test1'},
      {path: '/test2',    component: () => import('../pages/testpage2.vue'), name: 'test2'},
      {path: '/test3',    component: () => import('../pages/testpage3.vue'), name: 'test3'},
      {path: '/test4',    component: () => import('../pages/testpage4.vue'), name: 'test4'},
      {path: '/test5',    component: () => import('../pages/testpage5.vue'), name: 'test5'},
      {path: '/test6',    component: () => import('../pages/testpage6.vue'), name: 'test6'}
    ]
  }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})
export default router

and

<p>Current route: {{ route.path }}</p> <!--  Current route: /test6 -->

to show the route on the UI and to make components show as active:

:active="route.name === 'search'"

What helped me was this example.