react和vue都是比较热门的前端框架,对于一些初始数据的加载,应该放在那个生命周期中调用比较合适?给出结论前,先大致介绍下两个框架的生命周期及执行顺序。
一.react和vue的生命周期
1.react的生命周期
react的的生命周期包括
construct, componentWillMount, render,
componentDidMount, componentWillReceiveProps, shouldComponentUpdate,
componentWillUpdate, componentDidUpdate, componentWillUnmount
1.1 初次加载(无state更新)执行的生命周期执行顺序
construct => componentWillMount => render => componentDidMount
//componentWillMount 在官网中指出后面会被废除
若是有父组件 子组件的嵌套,那么总体执行的生命周期为
父 construct => 父 componentWillMount => 父 render =>
子 construct => 子 componentWillMount => 子 render =>
子 componentDidMount => 父 componentDidMount
1.2 父组件更新setState时候的生命周期执行顺序
父 componentWillUpdate => 父 render => 子 componentWillReceiveProps =>
子 componentWillUpdate => 子 render => 子 componentDidUpdate =>
父 componentDidUpdate
注意:1.不要在componentWillUpdate,render中触发setState,会造成死循环
2.componentWillReceiveProps生命周期只在子组件存在,它有一个参数nextProps,父组件传递给子组件的this.props对象其实和componentWillReceiveProps的nextProps是一样的,都是最新的
2.vue的生命周期
相较于react,vue的生命周期要简单许多,分为 创建前 beforeCreate,创建后created, 挂载前beforeMount,挂载后mounted,更新前beforeUpdate,更新后updated,销毁前beforeDestroy,销毁后destoryed
beforeCreate => state(data、computed等) => created => beforeMount => mounted =>
beforeUpdate => updated => beforeDestroy => destoryed
2.1 单个组件生命周期
beforeCreate => state( props => methods =>data => computed => watch) =>
created => beforeMount => mounted => beforeUpdate
=> updated => beforeDestroy => destroyed
//vue内置的方法 属性 的执行顺序 props => methods =>data => computed => watch
2.2 父子组件初次渲染的生命周期
父 beforeCreate => 父 created => 父 beforeMount => 子 beforeCreate
=> 子 created => 子 beforeMount => 子 mounted => 父 mounted
2.3 子组件更新的生命周期
父 beforeUpdate => 子 beforeUpdate => 子 updated => 父 updated
2.4 父组件更新的生命周期
父 beforeUpdate => 父 updated
2.5 组件销毁过程
父 beforeDestroy => 子 beforeDestroy => 子 destroyed => 父destroyed
二. react和vue初始数据加载
1.react初始数据加载
react项目中初始数据加载一般放在componentDidMount中调用!
1.1 construct生命周期
constructor是用作组件state初绐化工作的,一些初始state状态都放在construct中。
组件准备挂载前最初加载的就是constructor,所以此时组件还未挂载到网页中。在此生命周期中调用后台数据,若调用时间过长,或者调用出错,就会阻塞组件的渲染,导致页面挂掉。
不过与组件上的数据无关的加载,是可以在constructor里加载的。
1.2 componentWillMount生命周期
在componentWillMount这个生命周期里调用setState方法不会触发组件重新渲染,而且若是未设置初始状态,用户体验也不好。所以它一般不会在这个生命周期中来加载数据,官网后面也会将此生命周期弃用。
当然若是同步的数据调用,放在此生命周期中执行也是可以的。
1.3 componentDidMount生命周期
组件完成挂载后才调用componentDidMount方法,在此方法中调用接口可以保证数据的加载正常进行,另外在这个方法中调用setState会触发组件的重新渲染。官方设计这个方法就是用来加载外部数据用的,或处理其他的副作用代码。
所以在componentDidMount()中调用接口能保证你的组件已经正确渲染。
综上所述,constructor是用作组件state初绐化工作的,初始数据加载就放在componentDidMount中调用。对于同步的数据调用是可以放在componentWillMount中的,但是异步的调用最好就放在componentDidMount中了。
2.vue初始数据加载
vue项目中初始数据加载一般放在mounted中调用!
2.1 beforeCreate生命周期
在此生命周期中拿不到任何信息,无法篡改数据,一般做loding,这个时候的vue实例还什么都没有,但是$route对象是存在的,可以根据路由信息进行重定向之类的操作
2.2 created生命周期
此时el没有初始化,数据已加载完成,可以在此生命周期中篡改数据,并更新。不会触发beforeUpdate,updated,在这结束loading,还做一些初始化,实现函数自执行。此时DOM还未挂载,无法对DOM进行操作,$ref属性内容为空数组
2.3 beforeMount生命周期
此时el已被初始化,数据已加载完成,可以在此生命周期中篡改数据,并更新。不会触发beforeUpdate,updated,在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数。
2.4 mounted生命周期
此时el已被初始化,数据已加载完成,可以在此生命周期中篡改数据,并更新。并且触发beforeUpdate,updated。一般在这发起后端请求,拿回数据,配合路由钩子做一些事情,此时DOM元素已经被挂载到组件上,可以进行DOM操作,$ref属性可以访问。
综合上述,一般初始请求放在mounted中,在mounted 生命周期中dom已拿到,可以进行DOM操作。在created 做则可以做一些简单的请求,但不能操作DOM。
3.路由加载的几种方式
3.1 常规import..from...加载
由vue-cli脚手架搭建的项目,默认的就是这种正常加载路由的方式,这种方式会将路由里所有的component打包成一个js,在刚进入页面时,会将所有的组件都加载出来,导致页面加载较慢。
import chatIndex from '@/views/chatIt/chatIt.vue'
{
path: '/chatindex',
name: '聊天首页',
component: chatIndex,
},
3.2 按需加载的3种方式
按需加载路由,会将你的component分别打包成不同的js,加载的时候也是按需加载,只用访问这个路由网址时才会加载这个js,就避免进入首页时加载内容过多,性能有所提升。
1.vue的异步组件
{
path: '/chatindex',
name: 'chatindex',
component: resolve => require(['@/views/chatIt/chatIt.vue'], resolve)
}
2.ES6的import
{
path: '/chatindex',
name: 'chatindex',
component: () => import('@/views/chatIt/chatIt.vue')
}
3.webpack的require.ensure()
使用webpack的require.ensure技术,也可以实现按需加载。
这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件;如果不指定chunkName,则和使用vue的异步组件一样,每个组件生产打包成一个js文件。
这个组件 chatindex 和下面的 Hello 组件,指定了相同的chunkName(名字为:demo),因此会合并打包成一个js文件。
{
path: '/chatindex',
name: 'chatindex',
component: resolve => require.ensure([], () => resolve(require('@/views/chatIt/chatIt.vue'),'demo')
},
{
path: '/hello',
name: 'hello',
component: resolve => require.ensure([], () => resolve(require('@/views/hello/hello.vue'),'demo')
}