React 15
四个核心流程
- 挂载
- constructor
- componentWillMount
- render
- componentDidMount
- 更新(父组件触发)
- componentWillReceiveProps
- shouldComponentUpdate(true)
- componentWillUpdate
- render
- componentDidUpdate
- 更新(组件内部触发)
- shouldComponentUpdate(true)
- componentWillUpdate
- render
- componentDidUpdate
- 卸载
- componentWillUnmount
主要函数介绍
-
constructor(props)
-
componentWillMount()
-
componentWillReceiveProps(nextProps)
- 触发不是因为传递 props 变化,而是父组件只要被 re-render(重渲染),那么子组件的 componentWillReceiveProps 就会被执行
-
shouldComponentUpdate(nextProps, nextState)
- 返回布尔类型,如果该方法返回值为 false,则可以跳过更新,不执行后续的生命周期方法
-
componentDidMount()
-
componentWillUpdate(nextProps, nextState)
-
componentDidUpdate(prevProps, prevState, snapshot)
- 传入的不是下一次的属性和状态,而是上一次的。当前的需要从this对象上获取
-
render()
-
componentWillUnmount()
- 会在组件被销毁时执行
- 在父组件中被移除
- 组件被设置了 key 值,父组件在 render 的过程发现 key 与上一次的不一致,那么这个组件也会被销毁,然后被重新初始化,重新设置 key 值
- 会在组件被销毁时执行
React16.3/React16.4
四个主要流程
- 挂载
- constructor
- getDerivedStateFromProps(null)
- render
- componentDidMount
- 更新(父组件触发)
- getDerivedStateFromProps(null)
- shouldComponentUpdate(true)
- getSnapshotBeforeUpdate
- render
- componentDidUpdate
- 更新(组件内部触发)
- getDerivedStateFromProps(null)
- shouldComponentUpdate(true)
- getSnapshotBeforeUpdate
- render
- componentDidUpdate
- 卸载
- componentWillUnmount
主要函数解读
-
constructor(props)
-
static getDerivedStateFromProps(props, state)
- 目的不是为了替换
componentWillMount,而是为了替换componentWillReceiveProps。该方法是一个静态方法(static),静态方法不依赖于组件的实例而存在,所以无法在方法内部读取this对象,而且它应该返回一个新的对象,或者一个null值,它存在的目的有且仅有一个:使用 props 来派生/更新 state,所有不是以此为目标的使用方式原则上来说都是错误的。 getDerivedStateFromProps不仅是在更新阶段会被调用,在挂载阶段也会被调用,这是因为派生 state 的诉求不仅仅在更新时存在,在初始化 state 时也会有需求。通过该方法派生 state 不会引起 render 函数重复执行。
- 目的不是为了替换
-
shouldComponentUpdate(nextProps, nextState)
-
getSnapshotBeforeUpdate(prevProps, prevState)
- 提供了一个时机读取当前 DOM 的一些信息,并把返回的值赋值给
componentDidUpdate方法的snapshot参数,主要用来处理 UI 显示,比如某些区域的滚动位置信息等。
- 提供了一个时机读取当前 DOM 的一些信息,并把返回的值赋值给
-
componentDidMount()
-
componentDidUpdate(prevProps, prevState, snapshot)
-
render()
-
componentWillUnmount()
变化及原因
流程上
- render 阶段:纯净且没有副作用,可以被 React 暂停,终止或重新启动
- pre-commit 阶段:可以读取 DOM
- commit 阶段:可以使用 DOM,运行副作用,安排更新
总体来说就是,render 阶段在执行过程中允许被打断,commit 阶段则总是同步执行。之所以确定这样的标准也是有深入考虑的,在 render 阶段的所有操作一般都是不可见的,所以被重复打断与重新执行,对用户来说是无感知的,在 commit 阶段会涉及到真实 DOM 的操作,如果该阶段也被反复打断重新执行,会导致 UI 界面多次更改渲染,这是绝对要避免的问题。
函数上
-
废弃
componentWillMount方法- 因为这个方法实在是没什么用
-
废弃
componentWillReceiveProps新增getDerivedStateFromProps- 简化派生 state 的代码
componentWillReceiveProps方法仅仅在更新阶段才会被调用,而且在此函数中调用 setState 方法更新 state 会引起额外的 re-render,如果处理不当可能会造成大量无用的 re-rendergetDerivedStateFromProps是做减法,是 React 在推行只用 getDerivedStateFromProps 来完成 props 到 state 的映射这一最佳实践,确保生命周期函数的行为更加可控可预测,从根源上帮助开发者避免不合理的编程方式,同时也是在为新的 Fiber 架构 铺路。
-
废弃
componentWillUpdate新增getSnapshotBeforeUpdate- componentWillUpdate 是 Fiber 架构落地的一块绊脚石,不得不废弃掉。
-
新增
getDerivedStateFromError与componentDidCatch错误处理函数
原因解读
看一下被废弃的生命周期函数:
- componentWillMount
- componentWillUpdate
- componentWillReceiveProps
这些生命周期的共性就是它们都处于 render 阶段,都可能被暂停,终止和重新执行。而如果开发者在这些函数中运行了副作用(或者操作 DOM),那么副作用函数就有可能会被多次重复执行,会带来意料之外的严重 bug。
总结就是:
- 为 Fiber 架构落地清除障碍,引入增量渲染的机制解决同步渲染引起的应用卡顿风险
- 以废弃改进 API 的方式避免开发者滥用生命周期函数,推行强制性的最佳实践(每一个值有且仅有一个明确的来源)
Fiber架构
-
原因:React v16 之前,每触发一次组件的更新,都会构建一棵新的虚拟 DOM 树,通过与上一次的虚拟 DOM 树进行 Diff 比较,实现对真实 DOM 的定向更新。这一整个过程是递归进行的(想想 React 应用的组织形式),而同步渲染的递归调用栈层次非常深(代码写得不好的情况下非常容易导致栈溢出),只有最底层的调用返回,整个渲染过程才会逐层返回。这个漫长的更新过程是不可中断的,同步渲染一旦开始,主线程(JavaScript 解析与执行)会一直被占用,直到递归彻底完成,在此期间浏览器没有办法处理任何渲染之外的事情(比如说响应用户事件)。这个问题对于大型的 React 应用来说是没办法接受的。
-
原理:Fiber 会将一个大的更新任务拆解为许多个小任务。每一个小任务执行完成后,渲染进程会把主线程交回去(释放),看看有没有其它优先级更高的任务(用户事件响应等)需要处理,如果有就执行高优先级任务,如果没有就继续执行其余的小任务。通过这样的方式,避免主线程被长时间的独占,从而避免应用卡顿的问题。这种可以被打断的渲染过程就是所谓的异步渲染。
-
特点:Fiber 带来了两个重要的特性:任务拆解 与 渲染过程可打断。关于可打断并不是说任意环节都能打断重新执行,可打断的时机也是有所区分的。根据能否被打断这一标准,React v16 的生命周期被划分为了 render 和 commit 两个阶段(commit 又被细分为 pre-commit 和 commit)。
React16.8
主要变化
新增Hooks。Hooks 能够让函数组件拥有使用与管理 state 的能力,也就演化出了函数组件生命周期的概念(render 之外新增了其他过程),涉及到的 Hook 主要有几个:useState、useMemo、useEffect。
Hooks 与 生命周期函数对应关系:
原因解读
- 复用:便于分离与复用组件的状态逻辑(Mixin,高阶组件,渲染回调模式等)
- 副作用:复杂组件变得难以理解(状态与副作用越来越多,生命周期函数滥用)
- this: 类组件中难以理解的 this 指向(bind 语法)
- 优化:类组件难以被进一步优化(组件预编译,不能很好被压缩,热重载不稳定)
参考资料:
- react生命周期介绍 baijiahao.baidu.com/s?id=171557…
- react生命周期图示 projects.wojtekmaj.pl/react-lifec…