[Translation] Understanding fetch in Nuxt 2.12

Posted May 25, 20207 min read

In the process of researching the Nuxt source code, it was found that the operation process of fetch was completely different from what the official website said, so I went to the English official website as soon as I moved ... Sure enough, Nuxt 2.12 updated fetch, which can be said to have completely changed. It is more powerful and easy to use, but the document on the Chinese official website is still 2.11.X and has not been updated. After reading the English documentation, I found this [blog]on the official website( https://zh.nuxtjs.org/blog/understanding-how-fetch-works-in-nuxt-2-12 ), which is very good, I think Translated to give a reference for students who study Nuxt. After all, there are basically no Chinese materials at present. They are limited to the level. Please indicate if there are errors.

Introduction

Nuxt introduced a new method-fetch in the latest 2.12 release. Fetch provides a completely new way to introduce data into Nuxt applications. In this article, we will explore the different functions of the fetch hook and try to understand how it works.

Fetch hook function & Nuxt life cycle

Nuxt's hook function fetch runs after the create hook function in Vue. As we know, all Vue lifecycle hook functions are called in their corresponding this context, and fetch is no exception .

Life Cycle
The Fetch hook function is called after the server-side component is instantiated, which allows the fetch function to refer to the component's instance object through this.

export default {
  fetch() {
    console.log(this);
  }
};

Let me see what this means for page components.

For page components

With the help of this context, fetch can directly change the data of the component, which means we can directly set the local data of the component without using external storage like Vuex to store the data.

In this way, Vuex becomes an option. Of course, if you need to use it, you can still use this. $Store to access it.

Fetch hook function availability

Through the fetch function, we can prefetch asynchronous data in any Vue component, which means that the limitation that can only be used before the Vue component in the page directory is gone, and all Vue components can use the fetch function. For example, the vue components in the/layouts and/components directories.
Let s take a look at what this means for the layouts and building-block components

Layout components

By using the new fetch function, we can make API calls directly from the layout component. This was not possible before v2.12 was released.
Usage of some examples:

  • Get configuration data from the backend, then dynamically generate footer and navigation bar
  • Obtain user-related information, such as user information and the number of items in the shopping cart
  • You can get site-related data at layouts/error.vue

building-block(child, nested) component

Because the hook function can be used in the sub-component, so we can hand over all the data acquisition tasks previously performed in the page component to the sub-component fetch function.
This greatly reduces the task of routing page components.
We can still use props to pass data to sub-components, but if sub-components need their own data-grabbing logic, it is now feasible!

Run order of multiple hook functions

Since each component can have its own data acquisition logic, you may ask, what is the calling sequence of each component?
The Fetch hook is called once on the server side(on the first request of the Nuxt application, and then called when the client navigates to another path. But since we can define a fetch hook for each component, the fetch hook is pressed The order of its hierarchy is called.(Translation:the hook function of page runs before the hook function of components)

Disable fetch on the server

If you need it, you can easily disable the fetch function on the server side.

export default {
  fetchOnServer:false
};

Error handling

The new fetch error handling mechanism is at the component level. Let's see how it is implemented.
Because we are fetching data asynchronously, the new fetch `() provides an object to check whether the request is over and successful. <br /> This is what this object looks like-$fetchState `

$fetchState = {
  pending:true | false,
  error:null | {},
  timestamp:Integer
};

There are three attributes:

  1. Peding-allows you to display a placeholder(whether it is requesting) when the client calls fetch.
  2. Error-allows you to display error messages
  3. Timestamp -shows the timestamp of the last call to fetch, which is useful for components that use cache through keep-alive

These values can be used directly in the template of the component to display the Loding during data acquisition.

<template>
  <div>
    <p v-if = "$fetchState.pending"> Fetching posts ... </p>
    <p v-else-if = "$fetchState.error"> Error while fetching posts </p>
    <ul v-else>

    </ul>
  </div>
</template>

When an error occurs at the component level, we can set the HTTP status code on the server side by judging process.server in the fetch hook and use thethrow new Error()statement for subsequent processing.

async fetch() {
  const post = await fetch(`https://jsonplaceholder.typicode.com/posts/${this. $route.params.id}`)
                     .then((res) => res.json())

  if(post.id === this. $route.params.id) {
      this.post = post
    } else {
      //Set the status code on the server
      if(process.server) {
        this. $nuxt.context.res.statusCode = 404
      }
      //Then throw an error
      throw new Error('Post not found')
    }
}

Setting the HTTP status code in this way is helpful for correct SEO.

Fetch can also be called via methods

The new fetch hook also serves as a method, which can be called during user interaction or in methods.

<!-from template in template->
<button @click = "$fetch"> Refresh Data </  button>

//from component methods in script section
export default {
  methods:{
    refresh() {
      this. $fetch();
    }
  }
};

Enhance the performance of Nuxt pages

We can use the ::keep-alive-props`prop and activated hook functions to use fetch to make the page performance stronger
Nuxt allows to cache a certain number of pages and the data it fetches in memory. And you can also set the expiration time of these caches.
If we want to use the method mentioned above, we need to add keep-alive prop in the and components.

<!-layouts/default.vue->
<template>
  <div>
    <nuxt keep-alive />
  </div>
</template>

In addition, we can control the number of cached pages by adding:keep-alive-props.

<nuxt keep-alive:keep-alive-props = "{max:10}" />

The above is a more advanced and general method to improve the performance of the page. We can also optimize the call of the fetch request by using $fetchState.timestamp, mainly by comparing the timestamp of the last request, a more free caching strategy

export default {
  activated() {
    //If the last request exceeds one minute, the request is initiated again
    if(this. $fetchState.timestamp <= Date.now()-60000) {
      this. $fetch();
    }
  }
};

asyncData vs Fetch

For page components, the new fetch seems to be too similar to asyncData. Because they are all responsible for the processing of local data, but there are still some key differences worth noting, as follows:

AsyncData

  1. Only in page component(route level component) can use asyncData method

  2. asyncData is called before the component is instantiated, so it cannot be accessed

  3. Add data to the component through retrun

    export default {
    async asyncData(context) {

     const data = await context. $axios. $get(
       `https://jsonplaceholder.typicode.com/todos`
    );
     //`todos` does not need to be declared in data
     return {todos:data.Item};
     //`todos` will be merged with local data

    }
    };

New Fetch

  1. fetch can be used in all vue components

  2. fetch is called after the component is instantiated, you can access this

  3. You can directly modify the local data very easily

    export default {
    data() {

     return {
       todos:[]
     };

    },
    async fetch() {

     const {data} = await axios.get(
       `https://jsonplaceholder.typicode.com/todos`
    );
     //`todos` has to be declared in data()
     this.todos = data;

    }
    };

Fetch before Nuxt 2.12

If you have used nuxt for a while, you will find that the new fetch is completely different from the previous version.

Is this a destructive update(will it make the previous fetch unavailable)

Actually not, we can still pass the context parameter to fetch to use the fetch from the previous version, which means that it will not cause any destructive changes to your application.
Here are some comparisons between the old and new versions of fetch

  1. The timing of calling the hook

Old: Called before the component is instantiated, so this cannot be accessed
New: Called after the component is instantiated when accessing the route, you can access this

2 . This VS context

Old: We can access the Nuxt context on the page-level component, provided that the context is passed as the first parameter.

export default {
  fetch(context) {
    //
  }
};

NEW: We can access this context like a Vue client hook function without passing any parameters.

export default {
  fetch() {
    console.log(this.data);
  }
};
  1. Availability

Old: Can only be called on the server side in the page component(route-level component).
NEW: Can be used in any vue component to get asynchronous data.

  1. Fetch hook call sequence

Old: fetch can be called once on the server(when the first request arrives at the nuxt server), and in the client whenever it is navigated to the component containing fetch
New: The new fetch and the old fetch are actually the same call, but since the new fetch can be set in subcomponents, the calling sequence of fetch is based on their structural hierarchy.

  1. Error handling

Old:We used the context.error function. When an error occurs during the API call, a custom error page is displayed.
New:The new fetch uses the $fetchState object to handle errors in the template area during API calls. The error handling is at the component level.

Does this mean that in Nuxt 2.12 we cannot display custom error pages to users?
\ * \ *
Of course not, we can still use asyncData() in the page-level component, call this. $Nuxt.error({statusCode:404, message:'Data not found'}) to show the custom error page.

in conclusion

The new fetch hook function brings a lot of improvements and provides more flexibility to get data and organize routing levels and building block components in a whole new way!
When you are planning and designing a new Nuxt project and it needs to call multiple APIs in a route, it will definitely change your way of thinking.
I hope this article will help you become familiar with the new fetch feature. I am looking forward to what you can do with it.