AnathanPham / blog

随便写写
1 stars 0 forks source link

Fiber如何更新? #16

Open AnathanPham opened 3 years ago

AnathanPham commented 3 years ago

在盘古开天地的时候,只有一个fiber。这个fiber就是current的顶级fiber。 此后,当安排更新,便向从current顶级fiber复制(TODO:?)了一个fiber,称为workInProgress fiber。 然后就开始了父亲带着孩子的更新之旅。

TLDR;

  1. 两个父亲进场,更新workInProgress父亲。
  2. 比较新儿子和旧儿子。如果旧儿子和新儿子不是一类人,就把旧儿子家拆掉,断绝旧亲戚的关系。如果是一类人就把旧儿子赶走,新儿子搬进来住。
  3. 新儿子变成了父亲,作为父亲出征,一代代的如此反复。

beginWork

第一次对比这两个顶级fiber,他们一模一样,没有什么可比较的。对于父亲,只更新。 过程是获取fiber上的 update对象,把update应用到workInProgress fiber上。这时,workInProgress fiber是最新的。 最新的父亲,生的孩子也是最新的。所以新父亲生下来新孩子,而旧父亲,只能眼巴巴的看着,但旧父亲有旧孩子。 此时,差异出现了。新孩子(react元素)和旧孩子(fiber)。(那父亲们呢?父亲已经更新了。对比的目的是什么?是为了得到最新的fiber树,同时尽可能利用旧的fiber节点。对于两个顶级父亲,他们是相同类型的,所以复用并更新。)

如果新孩子和旧孩子类型相同,那么就复用。 对于类型相同的孩子,新的和旧的,区别在于props。(createElement(类型,props,...children),children实际是props的子属性) 怎么复用呢?新孩子复制旧孩子的属性,只更新props(props在新父亲生下新孩子的时候已经确定)。 此后,在下一轮。新孩子和旧孩子,摇身一变,都成了父亲。(除了pendingProps几乎一样,他们都是旧的。更新对象update还挂在身上)

如果新孩子和旧孩子类型不同。 新孩子和旧孩子不是一类人了,旧孩子和新孩子不在一家(同一个节点)住。旧孩子的亲人(sibling兄弟节点、child叶子节点),家具(state或hook、update对象)和新孩子没有任何关系了。 那么就把旧孩子删掉(标记删除,此时属于render阶段。最终的删除操作在commit阶段执行)。 新孩子,转化成的fiber的alternate属性为null。 下一轮,新孩子变身成workInProgress父亲,null代表current父亲。

AnathanPham commented 3 years ago

正常的讲

beginWork只是更新当前的fiber,并不关心它的子孙(只是返回子fiber)。 更新的前提是新旧fiber的类型相同,或者为null,否则更新没有意义。而不同类型的新旧fiber在上一轮更新中确定,即他们是上一轮更新结果(上一轮更新fiber的子fiber)。

一个fiber是否需要更新,需要检查外部状态(props、context)和内部状态(state)是否收到更新。

外部状态

props,这个比较特殊,因为props是createElement产生的。所以每当执行过createElement,props一定会改变,即使你没有对props做任何操作。createElement被执行源于该段代码(或JSX)祖先组件执行了render。如果祖先执行过render,react会认为该组件应该收到更新通知