Vue.js 3 Composition API Routing Tutorial

In this Vue tutorial we learn how the router works with the Composition API.

We cover how to create a reference to the router for programmatic navigation and access to route and query parameters.

Lesson Project

For this lesson, we’ll use a similar setup as the one we ended the Routing section with. You will need an app generated by the Vue CLI with the Router package installed .

To keep things simple, we will hold all the routes in the main.js file and the functionality will be split up into the following components.

  • src/App.vue will hold all the routes to the different views and back/forward functionality.
  • src/views/Home.vue is just our home page.
  • src/views/Users.vue lists an array of users with props to allow UserSingle to display them.
  • src/views/UserSingle.vue uses props to display each user.

The project should look as follows.

Example: project
project-name/
├── src/
|   ├── views/
|   |   ├── Home.vue
|   |   ├── Users.vue
|   |   └── UserSingle.vue
|   └── App.vue

The root App component will link to the views and include back/forward functionality.

Example: src/App.vue
<template>
  <div>
    <router-link :to="{ name: 'Home' }">Home</router-link> |
    <router-link :to="{ name: 'Users' }">Users</router-link>
  </div>

  <p>
    <button @click="$router.go(-1)">Go back 1 step</button>
    <button @click="$router.go(1)" >Go forward 1 step</button>

    <button @click="$router.push('/user/1')">Redirect to "/user/1"</button>
  </p>

  <router-view/>
</template>

The Home view only has a template block with an h2 element to help us identify the page.

Example: src/views/Home.vue
<template>
  <h2>Home page</h2>
</template>

The Users view stores an array of users in the data option of its config object. In the template block, it loops over each user and outputs a router link with the user’s id as a prop.

Example: src/views/Users.vue
<template>
  <h2>Users page</h2>

  <p v-for="user in users" :key="user.id">

    <router-link
      :to="{
        name: 'UserSingle',
        params: {
          id: user.id
        }
      }">
      ({{ user.id }}) {{ user.name }}
    </router-link>

  </p>
</template>

<script>
export default {
  data() {
    return {
      users: [
        { id: 1, name: 'John' },
        { id: 2, name: 'Jane' },
        { id: 3, name: 'Jack' },
        { id: 4, name: 'Jill' }
      ]
    }
  }
}
</script>

The UserSingle view specifies the id prop that it gets from the Users CODE view, and then outputs it in its template block.

Example: src/views/UserSingle.vue
<template>
  <h2>Single User page</h2>
  <p>The user id is: {{ id }}</p>
</template>

<script>
export default {
  props: ['id']
}
</script>

Finally, the main.js file has lazy loaded routes to the views we set up above.

Example: main.js
import { createApp   } from 'vue'
import App from './App.vue'

// import router functions
import { createRouter, createWebHistory } from 'vue-router'
// setup routes
const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      name: 'Home',
      component: () => import('./views/Home.vue')
    },
    {
      path: '/user',
      name: 'Users',
      component: () => import('./views/Users.vue')
    },
    {
      path: '/user/:id',
      name: 'UserSingle',
      props: true,
      component: () => import('./views/UserSingle.vue')
    }
  ]
})

const app = createApp(App)

// tell Vue to use router
app.use(router)
app.mount('#app')

If you run the example in the browser, you will be able to navigate around the app through the routes on each view.

Routing with the Composition API

When we refer to the router in the Options API, we use the special this.$router instance variable. Because this doesn’t refer to object instance in the Composition API, we need a different way.

To get that reference in the Composition API, the Router package gives us the useRouter method that we import and assign to a constant in the setup option.

Syntax: useRouter
<script>
import { useRouter } from 'vue-router'

export default {
  setup() {
    // get a reference to
    // the router in main.js
    const router = useRouter()
  }
}
</script>

Once we have the reference, we can replace all instances of this.$router with the reference.

Example: src/App.vue
<template>
  <div>
    <router-link :to="{ name: 'Home' }">Home</router-link> |
    <router-link :to="{ name: 'Users' }">Users</router-link>
  </div>

  <p>
    <!-- Use router.go()/push() instead of $router -->
    <button @click="router.go(-1)">Go back 1 step</button>
    <button @click="router.go(1)" >Go forward 1 step</button>

    <button @click="router.push('/user/1')">Redirect to "/user/1"</button>
  </p>

  <router-view/>
</template>

<script>
import { useRouter } from 'vue-router'

export default {
  setup() {
    const router = useRouter()

    return { router }
  }
}
</script>

If we run the example in the browser, everything will still work as before.

We can also use the reference inside the setup option.

Example: src/App.vue
<template>
  <div>
    <router-link :to="{ name: 'Home' }">Home</router-link> |
    <router-link :to="{ name: 'Users' }">Users</router-link>
  </div>

  <p>
    <button @click="stepTo(-1)">Go back 1 step</button>
    <button @click="stepTo(1)" >Go forward 1 step</button>

    <button @click="pushTo('/user/1')">Redirect to "/user/1"</button>
  </p>

  <router-view/>
</template>

<script>
import { useRouter } from 'vue-router'

export default {
  setup() {
    const router = useRouter()

    function stepTo(step)  { router.go(step)   }
    function pushTo(route) { router.push(route)}

    return {
      stepTo,
      pushTo
    }
  }
}
</script>

The example above is rather silly but it serves as a simple example. In real world applications we mostly redirect from forms this way.

How to get the current route info

The Router package allows us to get information about the current route (the one we’re on) by getting a reference to it. To get the reference we use the useRoute method.

Example: useRoute
<script>
import { useRoute } from 'vue-router'

export default {
  setup() {
    // get a reference to
    // the current route
    const route = useRoute()
    }
  }
}
</script>

To demonstrate, we’ll use the UserSingle component, which gets the id prop from a route and outputs it on the page.

We can replace the prop by getting the id from the route.params object.

Example: replace id prop with params.id
<template>
  <h2>Single User page</h2>
  <p>The user id is: {{ id }}</p>
</template>

<script>
import { useRoute } from 'vue-router'

export default {
  // replace this
  // props: ['id'],
  setup() {
    const route = useRoute()

    return {
      // with params.id
      id: route.params.id
    }
  }
}
</script>

If we run the example in the browser and navigate to any of the users, they will still display the correct user id.

Further Reading

For more information on the topics covered in this lesson, please see the relevant sections below.