Watch Vue route params/query with Composition API

David Meir-Levy
Vue.js Developers
Published in
2 min readMar 19, 2020

This is a short post, but keep it for later.

When you move to Vue Composition API, sometimes you want to watch on query params or route URL params.
The main problem is that route has a new object on every route change, and it’s not an observable/reactive, so you can’t directly watch it.

Here are several ways to watch it anyway.

First solution: Direct watch

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

It will work because watch hook is using the Vue component’s instance with the regular watch object. It worked then, and it will still work here.

Second solution: “Propify” the route params

Consider this Vue Router object:

const router = new VueRouter({
routes: [{
path: 'article/:articleId'
component: Article,
props: (route) => {articleId: route.params.articleId}
}]
})

The fact that we made the articleId to be given from the props — it became reactive! Because as you should already know, the props are reactive.

Now, I’ll make the same component from the first solution, but with the given props:

setup(props) {
const article = reactive({...});
function fetchArticle(id) {
//assign article..
}
watch(() => props.articleId, fetchArticle)
return { article };
}

This solution is great, but I found it’s a bit problematic to use with Nuxt.
Also, only the routed component gets the route params as a prop, so it wouldn’t work for child-components.

Third solution: Make a state from the route

If you want a way that will work for parent and child components, and also you want to abandon the “stringed” watcher (like the first solution), there is another way — create a state from the route params, to make it watchable for everything.

Consider the router:

export const router = new VueRouter({
routes: [{
path: 'article/:articleId'
component: Article,
}]
})

Now consider this composition file:

import Vue from 'vue';
import { computed } from '@vue/composition-api';
import { router } from '../router';
const routeData = Vue.observable({params: {}, query: {}});router.afterEach(route => {
routeData.params = route.params;
routedata.query = route.query;
});
function useParams() {
return computed(() => routeData.params)
}

After we made this kind of state, we can read it from everywhere in our application. For example:

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

In that solution, we made a reactive object that is mutated on route changes, which is what Vue Router didn’t gave us out of the box.

Enjoy! :)

--

--