# 序
用惯了 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
import React, { Component } from 'react'; | |
class App extends Component { | |
state = { | |
name: 'biu', | |
}; | |
} | |
export default App; |
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,简单说,就是一个纯函数
static getDerivedStateFromProps(nextProps, prevState) { | |
// 根据 nextProps 和 prevState 计算出预期的状态改变,返回结果会被送给 setState | |
} |
getDerivedStateFromProps 是 componentWillReceiveProps 的替代品,但是前者比后者更安全,因为不能访问 this,就可以避免开发者做很多预料之外的操作,因为这个 hook 的设计初衷是根据 props 更新 state
# getSnapshotBeforeUpdate()
这函数会在 render 之后执行,而执行之时 DOM 元素还没有被更新,开发者可以在这时获取 dom 的一些信息 (比如保存网页滚动条位置)
函数的返回值会作为 componentDidUpdate 的第三个参数传入
getSnapshotBeforeUpdate(prevProps, prevState) { | |
console.log('#enter getSnapshotBeforeUpdate'); | |
return 'foo'; | |
} | |
componentDidUpdate(prevProps, prevState, snapshot) { | |
console.log('#enter componentDidUpdate snapshot = ', snapshot); | |
} |
# 参考
React 生命周期
React v16.3 之后的组件生命周期函数