React组件的生命周期
序
用惯了vue用react的生命周期总有一丝怪异啊,不过这并不妨碍我记点笔记
生命周期仅存在于类组件中,函数组件每次调用都是重新运行函数,旧的组件会被立刻销毁
旧版生命周期
总览
旧版生命周期对应React的版本小于16.3
constructor(props, context, updater)
React借用class类的constructor充当初始化钩子。
React规定constructor有三个参数,分别是props、context和updater。
- props是属性,它是不可变的。
- context是上下文
- updater是包含一些更新方法的对象,this.setState最终调用的是this.updater.enqueueSetState方法,this.forceUpdate最终调用的是this.updater.enqueueForceUpdate方法,所以这些API更多是React内部使用,暴露出来是以备开发者不时之需。
在React中,constructor需要先调用super(props),用于初始化this和props,详情可以看这里
constructor生命周期钩子中可以初始化this.state。
也可以使用下面的代码初始化state
1 | import React, { Component } from 'react'; |
constructor只会在组件创建时调用一次,之后的组件更新不会再调用constructor
componentWillMount()
这是组件挂载到DOM之前的生命周期钩子。
在某些特殊情况下,这个函数有可能会被调用两次,
- 服务端渲染
- Fiber的Reconciliation过程中打断了这个生命周期
所以有可能出现一些bug,不过这个生命周期好像也没什么用,所以建议尽量不要使用
render()
作为一个组件,最核心的功能就是把元素挂载到DOM上,所以render生命周期钩子是一定会用到的。
render会返回一个虚拟DOM,这个虚拟DOM会被挂载到虚拟DOM树中,最终渲染到页面的真实DOM中
render可能不只运行一次,只要需要重新渲染,就会重新运行
在render中最好不要使用setState,因为可能会导致无限递归渲染
componentDidMount()
这是组件挂载到DOM之后的生命周期钩子,这个时候的组件已经就绪,你可以随心所欲的操作数据了
通常情况下,我们会将网络请求、启动计时器等初始化操作,书写到该函数中
componentWillReceiveProps(nextProps)
componentWillReceiveProps生命周期钩子只有一个参数,即更新后的props,这个生命周期不会在组件初始化时触发
该声明周期函数可能在两种情况下被触发:
- 组件接收到了新的属性。
- 组件没有收到新的属性,但是由于父组件重新渲染导致当前组件也被重新渲染。
同样,因为Fiber机制的引入,这个生命周期钩子有可能会多次触发。
shouldComponentUpdate(nextProps, nextState)
这个生命周期钩子用于指示React是否要重新渲染该组件(通过返回true或者false), 主要用于性能优化
shouldComponentUpdate生命周期钩子默认返回true。也就是说,默认情况下,只要组件触发了更新,组件就一定会更新。
如果开发者调用this.forceUpdate强制更新,React组件会无视这个钩子
componentWillUpdate(nextProps, nextState)
组件即将被重新渲染时调用这个钩子,具体来说是在shouldComponentUpdate生命周期钩子返回true,或者调用this.forceUpdate之后。
在componentWillUpdate中最好不要使用setState,因为可能会导致无限递归渲染
同样,因为Fiber机制的引入,这个生命周期钩子有可能会多次调用。
componentDidUpdate(nextProps, nextState)
这是组件更新之后触发的生命周期钩子,在这里可以拿到更新后的DOM
在componentDidUpdate中最好不要使用setState,因为可能会导致无限递归渲染
componentWillUnmount()
这是组件卸载之前的生命周期钩子,通常在该函数中销毁一些组件依赖的资源,比如计时器或者注册的全局事件
新版生命周期
总览
删除的API
- componentWillMount
- componentWillUpdate
- componentWillReceiveProps
旧版的生命周期函数非常的对称,有componentWilUpdate对应componentDidUpdate,有componentWillMount对应componentDidMount;也考虑到了因为父组件引发渲染可能要根据props更新state的需要,所以有componentWillReceiveProps。
但是,这个生命周期函数的组合在Fiber之后就显得不合适了,如果开启async rendering,在render函数之前的所有函数,都有可能被执行多次。所以为了安全考虑,react废弃了这三个API
static getDerivedStateFromProps(props, state)
getDerivedStateFromProps是一个静态函数,所以函数体内不能访问this,简单说,就是一个纯函数
1 | static getDerivedStateFromProps(nextProps, prevState) { |
getDerivedStateFromProps是componentWillReceiveProps的替代品,但是前者比后者更安全,因为不能访问this,就可以避免开发者做很多预料之外的操作,因为这个hook的设计初衷是根据props更新state
getSnapshotBeforeUpdate()
这函数会在render之后执行,而执行之时DOM元素还没有被更新,开发者可以在这时获取dom的一些信息(比如保存网页滚动条位置)
函数的返回值会作为componentDidUpdate的第三个参数传入
1 | getSnapshotBeforeUpdate(prevProps, prevState) { |