Screencasts
Home Tag Author Help

Using the Nuxt fetch method for effortless API sorting and filtering

If you've used Nuxt before, you're probably using the asyncData method in your pages to pre-fetch content from your API to be server-side rendered.

The new fetch method in Nuxt 2.12 does pretty much that, but has some added benefits that make working with re-fetching data a breeze.

I recently discovered this works amazingly well for mapping the query string in your client to your API.

If you have a few components that deal with sorting/filtering, they likely modify the query string in your client to look something like this:

?free=true&orderBy=date&orderDirection=asc&page=1

Passing these to your API on first page load is really simple with asyncData. (This example uses the query-string library to parse the query string so it can be sent to the API).

async asyncData ({ $axios, query }) {
    let courses = await $axios.$get('courses', queryString.stringify(query))

    return {
        courses
    }
}

Ideally though, you'd want to watch the query string and then re-trigger a fetch of this data, but asyncData can't be re-called once a component has been created and mounted.

This is where fetch comes in

I won't go into the details of fetch here, but in short:

  • It is called after the component is created in the Nuxt lifecycle. This means we have access to this.
  • It still allows content to be server-side rendered
  • It can be called as many times as you want (the important part)

This means that we can set up a watcher for our query string, and re-trigger the fetching of data, making our pages really, really clean and simple.

{
    // ... other page stuff
    
    watch: {
        '$route.query': '$fetch'
    },

    async fetch () {
        this.courses = await this.$axios.$get('courses', queryString.stringify(this.$route.query))
    }
}

By implementing the above, whenever the query string changes, we refetch data in exactly the same way, updating our component data.

Previously, we'd have needed to implement a separate method that hooks up to the watcher. That may look something like this.

{
    watch: {
        '$route.query' (query) {
            this.fetchCourses(query)
        }
    },

    methods: {
        async fetchCourses (query) {
            this.courses = await this.$axios.$get('courses', queryString.stringify(query))
        }
    },

    async asyncData ({ $axios, query }) {
        let courses = await $axios.$get('courses', queryString.stringify(query))

        return {
            courses
        }
    }
}

Because we can't re-fetch using asyncData, we would have to create another method that can be invoked by a watcher, leading to a little code duplication (or a lot of duplication, if things are more complicated than this).

I'm sure you'll agree, swapping out asyncData for fetch makes sense for this use case.

Further learning

There's so much more to fetch, so I'd recommend checking out the official documentation, and this excellent blog post for a general understanding of how it works.