为什么我们要学习组件的生命周期钩子函数?
- 生命周期钩子函数的使用可以帮助我们更好的控制和管理组件
16版本的生命周期
React生命周期分为四个阶段:
- 初始化阶段
- 更新阶段
- 卸载阶段
- 错误处理阶段【 React16.3版本之后新增 】
初始化阶段
4个钩子函数
-
constructor
触发时间: React组件的构造函数在挂载之前被调用
任务:
- 1. 通过调用super将父组件绑定在自己身上的属性赋值给 this.props , this.props = props
- 2. state的定义
- 3. 给普通函数绑定this , this.fn = this.fn.bind(this) (如果不进行bind的绑定,那么该实例方法的this值为undefined) -
componentWillMount/UNSAFE_componentWillMount
表示组件挂载前的准备工作(即将弃用) -
render
React中最核心的方法,一个组件中必须要有这个方法
触发时间:初始化阶段和更新阶段都会触发
任务:
- 1. 解析 this.state 和 this.props
- 2. jsx -> vdom对象模型 -
componentDidMount
调用时间: 组件挂载结束之后调用
任务:
- 1. 数据请求,然后赋值给state
- 2. 真实dom有了,可以做第三方实例化
更新阶段
触发条件: setState/forceUpdate
5个钩子函数
- componentWillReceiveProps(nextProps)/UNSAFE_componentWillReceiveProps
nextProps:代表新值
触发条件: 组件的props发生改变时触发
意义:
-1.用于获取最新的属性
-2.用于判断组件当前的属性是否改变过 - shouldComponentUpdate (nextProps,nextState)
-1.表示组件是否更新,这个钩子只要写,就必须有返回值,返回值是布尔值。true表示会触发重新渲染,false表示不会触发重新渲染,默认返回true
-2.这个钩子函数是性能优化的关键 - componentWillUpdate /UNSAFE_componentWillUpdate
表示组件即将更新 - render
更新阶段也会再次出发 - componentDidUpdate
表示组件更新结束,真实DOM又生成了
销毁阶段
触发时间: 当我们的组件被卸载或者销毁了就会调用
1个钩子函数
- componentWillUnmount
清除无用实例和事件
错误处理阶段
- componentDidCatch(error,info)
用于捕获子组件throw出来的错误
作用:
错误边界是React组件,可以在其子组件树中的任何位置捕获JavaScript错误,记录这些错误并显示回退UI,而不是崩溃的组件树。
注意事项:
一、初始化阶段
1.你的主线程任务是在生命周期前面执行的
2. 父子组件的初始化执行顺序
- 先父组件前三个,子组件全走完,父组件最后 componentDidMount
初始化父子组件8个生命周期的执行顺序:App-componentDidMount在最后是因为:这个钩子函数表示页面已经出来的,vdom变成了rdom,子组件也是App组件里的一部分
二、更新阶段
1.只要setState执行,那么更新阶段就触发
3. 能使用props绝不用state(因为在shouldComponentUpdate钩子函数中,只能判断属性的新旧值变化,无法判断状态的新旧值变化,this.state.xxx得到就是新值 )
4. props改变,触发5个钩子函数,state改变,触发四个钩子函数 (componentWillReceiveProps没有触发)
三、forceUpdate()
默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 render() 方法依赖于其他数据,则可以调用 forceUpdate() 强制让组件重新渲染。
注:这里的其他数据指的是定义在props和state外的数据
调用 forceUpdate() 将致使组件调用 render() 方法,此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发正常的生命周期方法,包括 shouldComponentUpdate() 方法。
通常你应该避免使用 forceUpdate(),尽量在 render() 中使用 this.props 和 this.state。
17版本新增的两个钩子函数
- static getDerivedStateFromProps(props, state)
作用 :
可以将属性转成状态
这里可以用this吗?
this是undefined ,因为这是静态方法,所以this不能用
static getDerivedStateFromProps(props, state) {
console.log('this',this)//undefined
//因为属性是不可改变的,所以转成状态方便修改
return props //将属性转成状态
}
- getSnapshotBeforeUpdate(prevProps, prevState)
调用时间: render结束之后,componentDidUpdate调用之前
作用:
这个函数有一个返回值,会作为第三个参数传递给componentDidUpdate
注意:
这个方法一定要和componentDidUpdate一起使用,否则控制台也会有警告
应用1:滚动条位置定位
getSnapshotBeforeUpdate(prevProps, prevState) {
//! 滚动条位置定位
window.onscroll = function (e) {
//注意:事件是异步的,所以下方return瞬间是拿不到这个值得,所以需要先存起来
localStorage.setItem('scrollTop',e.target.scrollingElement.scrollTop)
}
return 1000
}
comonentDidUpdate(prevProps, prevState,snapshot) {
//拿到的是上次滚动条高度记录的值
const scrollTop = localStorage.getItem('scrollTop')
}
应用2:数据请求
//请求数据 数据请求时异步的
getData = () => {
return new Promise((resolve,reject) => {
fetch('http://59.110.226.77:3000/api/list/hot?cid=17')
.then(res => res.json())
.then(data => {
resolve(data)
})
.catch(error => Promise.reject(error))
})
}
async getSnapshotBeforeUpdate(prevProps, prevState) {
const result = await this.getData()
return result
}
componentDidUpdate(prevProps, prevState,snapshot) {
snapshot.then(res => console.log(res))
}