fiber
fiber是react v16引入的新的组件描述方案.每当组件被使用时,react会为它生成一个fiber节点,描述了组件函数、props以及它在组件树的位置.
fiber节点还以链表形式存储当前组件实例的state.当函数第一次调用时,会按照初始值向后拓展链表,之后的每次调用都从对应的链表项中取值.setState会将当前实例的fiber节点标记为待更新并引起react更新fiber树.useEffect、useRef等也有对应的链表,原理与state类似.
由于hook与链表紧密相关,要求每次调用hook的顺序和数量都必须和第一次保持一致,因此不能出现在条件、循环等语句中.
渲染流程
分为调和(Reconciliation)与提交(Commit)两个阶段.
调和
更新fiber树.
react由上向下遍历树,寻找待更新节点,运行组件函数生成新组件,并与该节点对应的组件进行比对:
- 如果新旧组件的key不同,为新组件和它的所有子组件生成新的fiber子树,替换原有子树,停止向下的遍历过程
- 如果key相同,则新组件继承当前节点,并逐级向下比对所有子组件
- 子组件的函数与key都与相应旧组件相同才能继承节点并继续向下比对,否则也会生成新子树进行替换
- 如果存在子组件被memo判定为不需要更新,则停止向下比对,改为遍历该组件对应节点的子树,寻找待更新节点并重复这一过程
对于新增加的组件也会生成相应的fiber节点和子树
提交
将fiber树的修改提交至dom.提交后会执行副作用,包括被替换子树的节点对应组件的清理函数.
fiber 与 虚拟dom
fiber是虚拟dom的升级.
虚拟dom树在栈上递归地执行更改,会连续占用浏览器主线程时间,导致浏览器渲染卡顿.
fiber树则将整个树更新进行分片,使任务可以暂停,确保浏览器正常进行渲染任务.此外,任务分片还具有优先级,利用requestAnimationFrame执行高优先级的分片,requestIdleCallback执行低优先级的分片,保证用户操作响应快、网页渲染流畅.
fiber的优化:双缓冲技术
每当fiber树的一个节点更新时,react会为以它为根的子树生成一个替代树(就像以现有分支为基础创建一个新分支).之后所有的修改都在替代树上进行.完成更改后,替代树会被渲染至屏幕上并替代原有子树(就像新分支的更改合并到旧分支).此后,原有子树会作为新子树的替代树存在.后续更新也在这两棵子树间进行,不需要额外创建和回收变量.