react 16以前的生命周期是这样的
组件在首次渲染时会被实例化,然后调用实例上面的componentWillMount,render和componentDidMount函数。组件在更新渲染时可以调用componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate,render和componentDidUpdate函数。组件在卸载时可以调用componentWillUnmount函数。
借图:
从 React v16.3 开始,React 建议使用getDerivedStateFromProps和getSnapshotBeforeUpdate两个生命周期函数替代 componentWillMount,componentWillReceiveProps和componentWillUpdate三个生命周期函数。这里需要注意的是 新增的两个生命周期 函数和原有的三个生命周期函数必须分开使用,不能混合使用
目前的生命周期(借图):
componentWillMount存在的问题
有人认为在componentWillMount中可以提前进行异步请求,避免白屏。但是react在调用render渲染页面的时候,render并不会等待异步请求结束,再获取数据渲染。这么写是有潜在隐患的。
而在react fiber之后 可能在一次渲染中多次调用。原因是:react fiber技术使用增量渲染来解决掉帧的问题,通过requestIdleCallback调度执行每个任务单元,可以中断和恢复,生命周期一旦中断,恢复之后会重新跑一次之前的生命周期
新的生命周期
static getDerivedStateFromProps
getSnapshotBeforeUpdate
触发时间: update发生的时候,在render之后,在组件dom渲染之前。
返回一个值,作为componentDidUpdate的第三个参数。
配合componentDidUpdate, 可以覆盖componentWillUpdate的所有用法。
由于React渲染/更新过程一旦开始无法中断,持续占用主线程,主线程忙于执行JS,无暇他顾(布局、动画),造成掉帧、延迟响应(甚至无响应)等不佳体验。fiber应运而生。
Fiber 是对react reconciler(调和) 核心算法的重构。关键特性如下:
增量渲染用来解决掉帧的问题,渲染任务拆分之后,每次只做一小段,做完一段就把时间控制权交还给主线程,而不像之前长时间占用。
Fiber tree
fiber树其实是一个单链表结构,child指向第一个子节点,return指向父节点,sibling指向下个兄弟节点。结构如下:
?1 2 3 4 5 6 7 8 | // fiber tree节点结构 { stateNode, child, return , sibling, ... } |
Fiber reconciler
reconcile过程分为2个阶段:
1.(可中断)render/reconciliation 通过构造workInProgress tree得出change
2.(不可中断)commit 应用这些DOM change(更新DOM树、调用组件生命周期函数以及更新ref等内部状态)
构建workInProgress tree的过程就是diff的过程,通过requestIdleCallback来调度执行一组任务,每完成一个任务后回来看看有没有插队的(更紧急的),每完成一组任务,把时间控制权交还给主线程,直到下一次requestIdleCallback回调再继续构建workInProgress tree
生命周期也被分成了两个阶段:
?1 2 3 4 5 6 7 8 9 10 | // 第1阶段 render/reconciliation componentWillMount componentWillReceiveProps shouldComponentUpdate componentWillUpdate // 第2阶段 commit componentDidMount componentDidUpdate componentWillUnmount |
第1阶段的生命周期函数可能会被多次调用,默认以low优先级执行,被高优先级任务打断的话,稍后重新执行。
fiber tree与workInProgress tree
双缓冲技术:指的是workInProgress tree构造完毕,得到的就是新的fiber tree,然后把current指针指向workInProgress tree,由于fiber与workInProgress互相持有引用,旧fiber就作为新fiber更新的预留空间,达到复用fiber实例的目的。
每个fiber上都有个alternate属性,也指向一个fiber,创建workInProgress节点时优先取alternate,没有的话就创建一个
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | let workInProgress = current.alternate; if (workInProgress === null ) { //... workInProgress.alternate = current; current.alternate = workInProgress; } else { // We already have an alternate. // Reset the effect tag. workInProgress.effectTag = NoEffect; // The effect list is no longer valid. workInProgress.nextEffect = null ; workInProgress.firstEffect = null ; workInProgress.lastEffect = null ; } |
这么做的好处:
fiber 中断 恢复
中断:检查当前正在处理的工作单元,保存当前成果(firstEffect, lastEffect),修改tag标记一下,迅速收尾并再开一个requestIdleCallback,下次有机会再做
断点恢复:下次再处理到该工作单元时,看tag是被打断的任务,接着做未完成的部分或者重做
P.S.无论是时间用尽“自然”中断,还是被高优任务粗暴打断,对中断机制来说都一样。
在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
setState调用时有时是同步的(settimeout,自定义dom事件),有时是异步的(普通调用)
React事件是通过事件代理,在最外层的 document上对事件进行统一分发,并没有绑定在真实的 Dom节点上。 而且react内部对原生的Event对象进行了包裹处理。具有与浏览器原生事件相同的接口,包括 stopPropagation() 和 preventDefault()。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
长按识别二维码并关注微信
更方便到期提醒、手机管理