大家好,我卡颂。
本文咱们来看React
外部Effects List
机制重构的前因后果。
浏览完本文,你能够把握React18
比照之前版本,Suspense
个性的差别及起因。
欢送退出人类高质量前端框架群,带飞
什么是副作用
繁难的React
工作原理能够概括为:
- 触发
更新
- render阶段:计算
更新
会造成的副作用
- commit阶段:执行
副作用
副作用
蕴含很多类型,比方:
Placement
指DOM节点的插入与挪动
Passive
指useEffect
回调执行ChildDeletion
指移除子DOM节点
- 等等
更新造成DOM
变动次要就是Placement
、ChildDeletion
在起作用。
那么render阶段
如何保留副作用
,commit阶段
又是如何应用副作用
的呢?
Effects List
在重构前,render阶段
,带有副作用
的节点会连贯造成链表,这条链表被称为Effects List
。
比方下图,B、C、E存在副作用
,连贯造成Effects List
:
commit阶段
不须要从A向下遍历整棵树,只须要遍历Effects List
就能找到所有有副作用
的节点并执行对应操作。
SubtreeFlags
在重构之后,会将子节点的副作用
冒泡到父节点的SubtreeFlags
属性。
比方B、C、E蕴含的副作用
如下图:
冒泡流程如下:
- B的
副作用
为Passive
,冒泡到A,A.SubtreeFlags
蕴含Passive
- E的
副作用
为Placement
,冒泡到D,D.SubtreeFlags
蕴含Placement
- D冒泡到C,
C.SubtreeFlags
蕴含Placement
- C的
副作用
为Update
,C.SubtreeFlags
蕴含Placement
,C冒泡到A - 最终
A.SubtreeFlags
蕴含Passive
、Placement
、Update
这就代表A的子树中蕴含这三种副作用。
在commit阶段
,再依据SubtreeFlags
一层层查找有副作用
的节点并执行对应操作。
可见,SubtreeFlags
须要遍历树,而Effects List
只须要遍历链表,效率更高。那么React
为什么要重构呢?
Suspense
答案是:SubtreeFlags
遍历子树的操作尽管比Effects List
须要遍历更多节点,然而React18
中一种新个性恰好须要遍历子树。
这个个性就是Suspense
。
Suspense
是v16
就提供的性能,但v18
之后,当开启并发性能,Suspense
与之前版本的行为是有区别的。
思考如下组件:
<Suspense fallback={<h3>loading...</h3>}> <LazyCpn /> <Sibling /></Suspense>
其中LazyCpn
是应用React.lazy
包裹的异步加载组件
。
Sibling
代码如下:
function Sibling() { useEffect(() => { console.log("Sibling effect"); }, []); return <h1>Sibling</h1>;}
因为Suspense
会期待子孙组件中的异步申请结束后再渲染,所以当代码运行时页面首先会渲染fallback
:
<h3>loading...</h3>
然而Sibling
并不是异步的!这里就体现了新旧版本React
的差别。
新旧版React的差别
再回顾下开篇介绍的繁难React
工作原理:
- 触发
更新
- render阶段:协调器计算
更新
会造成的副作用
- commit阶段:渲染器执行
副作用
在开启并发之前,React
保障一次render阶段
对应一次commit阶段
。
所以在上例中,尽管因为LazyCpn
在申请导致Suspense
渲染fallback
,然而并不会阻止Sibling
渲染,也不会阻止Sibling
中useEffect
的执行。
控制台还是会打印Sibling effect。
同时,为了在视觉上显得Sibling
没有渲染,Sibling
渲染的DOM节点
会被设置display: none
:
但这其实挺hack
的。毕竟依据Suspense
的理念,如果子孙组件有异步加载的内容,那应该只渲染fallback
(而不是同时渲染display: none
的内容)
所以在新版中,针对Suspense
内不显示的子树做了独自的解决,既不会渲染display: none
的内容,也不会执行useEffect
回调:
要实现这部分解决的根底,就是扭转commit阶段
遍历的形式,也就回到开篇提到的Effects List
重构为subtreeFlags
。
你能够从这个在线Demo直观的感触新旧版Suspense
的差别
总结
明天咱们又学到了一个React
源码小常识。
值得一提的是,针对Suspense
的这次改良,为React
带来一种新的外部组件类型 —— Offscreen Component
。
将来他可能是实现React
版keep-alive
的根底。