前面的文章介绍了React 更新 render + commit的完整流程,下面来说一下一些优化策略。
bailout 即 熔断策略,即在BeginWork阶段,如果递到某个节点的子树, 如果该节点的子树已经不需要更新了,即和current保持一致了,那么可以直接熔断(bailout)当前Beginwork过程,复用current的子树即可。
如何确定子树不用更新了?
这个取决于四要素,即current节点和新Fiber节点的
- Props相等
- type相等代码
- 当前Fiber节点不包含当然renderedLane更新
- 如果当前节点是Context节点,需要相等 (这个先不用管)
我们主要看前三条,如何判断这三条是否满足bailout条件
Props & type
props和bailout判断条件如下,代码在react-reonciler/beginwork.ts -> beginWork函数
didReceiveUpdate = false;
const current = wip.alternate;
if (current !== null) {
/** 更新模式下 才检查是否bailout */
/** 检查props和type */
const prevProps = current.memorizedProps;
const wipProps = wip.pendingProps;
/**
* 注意 bailout的props直接检查对象地址是否相等
* 如果父节点存在更新 那么子节点无法bailout 需要通过childReconcile创建
* 那么子节点的 props一定和current.props不一样 因为createElement中传入的对象也不是相同地址 比如
* current createElement('div',{a:100}) -父节点不同,导致reconcilechild-> createElement('div',{a:100})
* 注意 虽然都是{a:100} 但是两个对象来源于两次render 其对象地址不同,这也就导致如果父节点没能bailout 子节点也无法bailout 就必须使用memo来shallowEqual
*/
if (prevProps !== wipProps || current.type !== wip.type) {
// 检查不通过
didReceiveUpdate = true;
} else {
... ... ...
}
}
可以看到,Props和type的判等简单的通过 "!==" 完成
beginWork维护一个全局变量didReceiveUpdate: boolean 并且将其封装成一个函数导出
/** 是否收到更新 默认为false 即没有更新 开启bailout */
let didReceiveUpdate: boolean = false;
/** 标记当前wip存在更新 不能bailout
* 导出接口 方便其他模块 (hooks) 使用 */
export function markWipReceiveUpdate() {
didReceiveUpdate = true;
}
markWipReceiveUpdate可以方便的在其他模块内导入,并且修改didReceiveUpdate的值
判断Update
如果Props和Type都没有变化,接下来会判断当前节点是否存在当前renderLane对应的更新。
if (prevProps !== wipProps || current.type !== wip.type) {
// 检查不通过
didReceiveUpdate = true;
} el

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



