Nuxt.js特有的两个生命周期:asyncData、fetch
您好,我是沧沧凉凉,是一名前端开发者,目前在掘金、知乎以及个人博客上同步发表一些学习前端时遇到的趣事和知识,欢迎关注。
最近帮同事找Nuxt项目问题时,发现Nuxt提供了2个生命周期,分别是:
- asyncData
- fetch
中文文档中对于这2个生命周期的介绍非常短,看完后我一头雾水,经过我的反复研究以及各种试验后,大致明白了这2个生命周期的用途和用法。
1. asyncData
asyncData方法会在组件(限于页面组件)每次加载之前被调用。它可以在服务端或路由更新之前被调用。在这个方法被调用的时候,第一个参数被设定为当前页面的上下文对象,你可以利用 asyncData方法来获取数据,Nuxt.js 会将 asyncData 返回的数据融合组件 data 方法返回的数据一并返回给当前组件。
简单的说,就是asyncData只能用于页面组件,不能用于自定义组件,它可以返回一个对象,该对象中的值会覆盖data中对应的属性值。
并且asyncData中没有this来引用组件实例,但是它有一个context参数,大致用法如下:
<template>
<div>{{ content }}</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
name: "IndexPage",
async asyncData({$axios}) {
const res = await $axios.$get("http://localhost:5000");
return {content: res.content};
},
data() {
return {
content: "",
};
},
});
</script>
查看网页源代码:
2. fetch
fetch 方法用于在渲染页面前填充应用的状态树(store)数据, 与 asyncData 方法类似,不同的是它不会设置组件的数据。
可以在任何组件中使用,无论是页面组件还是自定义组件。
需要注意的是,中文文档上面的内容已经过时了,由于过时的问题,带有非常强烈的误导性:
现在在fetch中是可以使用this获取到组件实例,并且也可以通过this去更改data中的属性。在英文文档中,官方对于fetch的介绍非常的完善,不像中文文档中是一段文字就给带过去了。
根据英文文档中,在Nuxt的2.12版本及之后,fetch的用法跟之前的版本完全不一样,而如果你在fetch中接受了一个context对象,那么它将被视为旧版的fetch,现在官方已经不推荐这么使用了。
我之前没有好好读英文文档,所以在试验的时候发现了一个坑点,直接看下面的代码吧:
async fetch() {
const res = await fetch('http://localhost:5000').then(res=>res.json());
// 这里赋值后界面正确渲染
this.content = res.content;
},
我改变请求方式后:
async fetch({ $axios }) {
const res = await $axios.$get('http://localhost:5000');
// 这里赋值后发现界面上并没有渲染出对应的值
this.content = res.content;
},
我把请求方式换成了Nuxt自带的axios,我发现页面上的内容没有正确的渲染出来,当时我完全没有找到原因所在。
而根据英文文档,在fetch中不能使用context,如果你使用了context参数,那么就会被视为旧版fetch。
如果你要使用context,那么推荐你使用asyncData或者匿名中间件,所以上面的请求应该这么写:
async fetch() {
// 从this中获取$axios而不是从context中获取
const res = await this.$axios.$get("http://localhost:5000");
// 这里界面上就能正确的渲染出数据
this.content = res.content;
},
查看网页源代码:
3. 传统请求
知道asyncData和fetch大致用法后,我们就得来看看为什么要用这两个生命周期进行请求,为什么不在created、mounted这种Vue中常用的生命周期中进行网络请求。
还是上面的请求:
async mounted() {
const res = await this.$axios.$get("http://localhost:5000");
this.content = res.content;
},
查看网页源代码:
可能你已经发现了区别,在mounted中进行请求,查看网页源代码的时候是看不到对应的数据,如果在网页源代码无法看到对应的数据,那么搜索引擎极大可能抓取不到这些数据。
如果你想要减小服务端的压力,比如一些对于SEO没有什么帮助的请求数据,那么你完全可以放在mounted中进行请求,因为mounted生命周期是在客户端进行运行的。
至于created这个生命周期,我实测的时候它会在服务端运行一次,然后又在客户端运行一次。
这可能关系到Nuxt生命周期的问题,我暂时就没有深入研究,所以没有发言权,而且官方也说的是如果你想要使用传统的Vue请求方式,那么将请求放在mounted生命周期中。
4. 用户信息
使用这2个生命周期,可以让你的项目获得更好的SEO,但是值得注意的是,这2个生命周期都是在服务端中运行,而服务端是没有window对象的,也就无法使用localstorage,如果要进行用户身份的验证,那么推荐是使用cookie来存储用户的身份信息。
使用js-cookie可以很方便的操作cookie。
5. 好处
现在很多搜索引擎的爬虫已经能够解析JavaScript文件,从而获取JavaScript文件上面重要的内容。
但是异步请求的数据是没有办法获取的,所以使用asyncData和fetch将一些重要的数据放在服务端进行请求,然后服务端返给客户端的HTML上就已经获取到了这些数据,这样有2个好处:
- 较短的白屏时间。
- 更好的SEO。
当很多数据是通过异步进行请求的时候,打开页面经常会出现页面坍缩,获取到数据渲染完成后页面才会正常显示,虽然可能就那么一瞬间,但是对于用户来说也会造成不好的体验。
而使用服务端渲染就不会有这些问题,因为数据已经在服务端获取完毕了,也就不会出现页面短暂坍塌的情况。
6. 最后
服务端渲染带来更好的SEO的同时,对于服务器的负担也是指数倍的,比如单页面应用布置到Nginx上面可能就占几M的内存,而如果是服务端渲染的情况下可能达到几百M甚至更多,要知道,服务器的内存可是非常贵的,内存每翻一倍,价格都要翻好几倍。
至于要不要做服务端渲染,还是得根据自身的情况来定,不过遇到官网这种外包项目,如果用的Vue技术栈那么选Nuxt肯定是没错的。
客户不做SEO,你可以打包成单页面应用,如果需要SEO,那你也可以毫无压力的开启服务端渲染,多做一手准备少加班。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!