Routing with Vue Router

Vue · Practical · 15 min

Any multi-page single-page app needs client-side routing, and Vue Router is the official solution.

Vue Router maps URL paths to components. You create a router with a history mode and a route table, install it with app.use(router), and render the matched component with <RouterView />:

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: Home },
    { path: '/users/:id', name: 'user', component: () => import('./UserPage.vue') },
  ],
})
  • createWebHistory() gives clean URLs (the server must serve index.html for unknown paths); createWebHashHistory() uses #/ URLs and needs no server config.
  • () => import(...) lazy-loads a route's component as a separate chunk.
  • Dynamic segments like :id appear in useRoute().params.id. The same component instance is reused when only params change, so watch () => route.params.id to reload data.
  • Nested routes use children plus a <RouterView /> inside the parent component.

Navigate declaratively with <RouterLink :to="{ name: 'user', params: { id: 7 } }"> (it adds active classes) or programmatically with useRouter().push('/').

Navigation guards control access: router.beforeEach((to) => { if (to.meta.requiresAuth && !isLoggedIn()) return { name: 'login' } }). Return false to cancel, a route to redirect, or nothing to continue. Per-component hooks like onBeforeRouteLeave help with "unsaved changes" prompts.

Example

// router.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from './views/Home.vue'

export const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', name: 'home', component: Home },
    { path: '/users/:id', name: 'user',
      component: () => import('./views/User.vue'),      // lazy chunk
      meta: { requiresAuth: true } },
    { path: '/:pathMatch(.*)*', component: () => import('./views/NotFound.vue') },
  ],
})

router.beforeEach((to) => {
  const loggedIn = Boolean(localStorage.getItem('token'))
  if (to.meta.requiresAuth && !loggedIn) return { name: 'home', query: { next: to.fullPath } }
})

// main.js: createApp(App).use(router).mount('#app')
// App.vue: <RouterLink :to="{ name: 'user', params: { id: 7 } }">Me</RouterLink>
//          <RouterView />
// User.vue: const route = useRoute(); route.params.id  // '7'

Remember

  • Define routes, app.use(router), render with <RouterView>
  • Lazy-load route components with () => import(...)
  • Params are in useRoute().params; watch them when the same component is reused
  • Guards return false, a redirect route, or nothing

Watch out for

  • Fetching data only in onMounted of a route component; navigating /users/1 to /users/2 reuses the instance and shows stale data.

Check yourself

  1. Navigating from /users/1 to /users/2 with the same route component. What happens by default?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: router.vuejs.org/guide/

Builds on

Unlocks

Nothing builds on this yet.