React源码阅读笔记6

beginWork:

验证当前 fiber 树是否需要更新
更新传入的节点类型进行对应的更新
更新后调和子节点

1.第一步验证当前 fiber 树是否需要更新:

  • 比较当前节点 props 是否有变化
  • 检查当前节点是否有更新或是否比当前 root 的更新优先级大
  • 没更新或优先级低就跳过,bailoutOnAlreadyFinishedWork
  • bailoutOnAlreadyFinishedWork 可以判断 current 是否有 child 更新
//  workInProgress.alternate   workInProgress下个将要更新的节点    本次优先级最大的节点  
function beginWork(current$$1, workInProgress, renderExpirationTime) {
  // 本身的过期时间   只有ReactDom.render时才有值
  var updateExpirationTime = workInProgress.expirationTime;
  //在当前节点 初次 渲染时为null
  if (current$$1 !== null) {
    var oldProps = current$$1.memoizedProps;
    var newProps = workInProgress.pendingProps;
    //判断props  context是否有修改
    if (oldProps !== newProps || hasContextChanged()) {
      // If props or context changed, mark the fiber as having performed work.
      // This may be unset if the props are determined to be equal later (memo).
      didReceiveUpdate = true;
    } else if (updateExpirationTime < renderExpirationTime) { //当前更新的优先级是否大于 fiber 节点上优先级最高的节点的优先级
      didReceiveUpdate = false;
      // This fiber does not have any pending work. Bailout without entering
      // the begin phase. There's still some bookkeeping we that needs to be done
      // in this optimized path, mostly pushing stuff onto the stack.
      
      ...
      
      //bailoutOnAlreadyFinishedWork 会判断这个 fiber 的子树是否需要更新,如果有需要更新会 clone 一份到      workInProgress.child 返回到 workLoop 的 nextUnitOfWork, 否则为 null
      return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);
    }
  } else {
    didReceiveUpdate = false;
  }
  
  ...
  
}

bailoutOnAlreadyFinishedWork:

 //bailoutOnAlreadyFinishedWork 会判断这个 fiber 的子树是否需要更新,
 如果有需要更新会 clone 一份到   workInProgress.child 返回到 workLoop 的 nextUnitOfWork, 否则为 null,代表可以直接complete了
function bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime) {
  cancelWorkTimer(workInProgress);

  if (current$$1 !== null) {
    // Reuse previous context list
    workInProgress.contextDependencies = current$$1.contextDependencies;
  }

  if (enableProfilerTimer) {
    // Don't update "base" render times for bailouts.
    stopProfilerTimerIfRunning(workInProgress);
  }

  // Check if the children have any pending work.
  var childExpirationTime = workInProgress.childExpirationTime;
  if (childExpirationTime < renderExpirationTime) {
    // The children don't have any work either. We can skip them.
    // TODO: Once we add back resuming, we should check if the children are
    // a work-in-progress set. If so, we need to transfer their effects.
    return null;
  } else {
    // This fiber doesn't have work, but its subtree does. Clone the child
    // fibers and continue.
    cloneChildFibers(current$$1, workInProgress);
    return workInProgress.child;
  }
}

回到 beginWork :

// 进行更新先把当前 fiber 的 expirationTime 设置为 NoWork
  workInProgress.expirationTime = NoWork;
  //workInProgress.type: 当函数组件时是 function  当为 class 组件时就是 class 构造函数  当 dom 原生组件时就是标签 div 这种字符串
  // pendingProps: 表示新的props
  //renderExpirationTime: fiberRoot.expirationTime,fiberRoot 上最大优先级的值
  //nextProps: workInProgress.pendingProps,此次更新带来的新 props
  switch (workInProgress.tag) {
    case IndeterminateComponent:
      {
        var elementType = workInProgress.elementType;
        return mountIndeterminateComponent(current$$1, workInProgress, elementType, renderExpirationTime);
      }
    case LazyComponent: //lazy组件只有在加载的组件还没完成之前才会被执行
      {
        var _elementType = workInProgress.elementType;
        return mountLazyComponent(current$$1, workInProgress, _elementType, updateExpirationTime, renderExpirationTime);
      }
    case FunctionComponent://函数 组件
      {
        var _Component = workInProgress.type;
        var unresolvedProps = workInProgress.pendingProps;
        var resolvedProps = workInProgress.elementType === _Component ? unresolvedProps : resolveDefaultProps(_Component, unresolvedProps);
        return updateFunctionComponent(current$$1, workInProgress, _Component, resolvedProps, renderExpirationTime);
      }
    case ClassComponent: //class 组件
      {
        var _Component2 = workInProgress.type;
        var _unresolvedProps = workInProgress.pendingProps;
        var _resolvedProps = workInProgress.elementType === _Component2 ? _unresolvedProps : resolveDefaultProps(_Component2, _unresolvedProps);
        return updateClassComponent(current$$1, workInProgress, _Component2, _resolvedProps, renderExpirationTime);
      }
    case HostRoot: //
return updateHostRoot(current$$1, workInProgress, renderExpirationTime); case HostComponent: //html 标签 return updateHostComponent(current$$1, workInProgress, renderExpirationTime); case HostText: //文本内容 return updateHostText(current$$1, workInProgress); case SuspenseComponent: return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime); case HostPortal: return updatePortalComponent(current$$1, workInProgress, renderExpirationTime); case ForwardRef: { var type = workInProgress.type; var _unresolvedProps2 = workInProgress.pendingProps; var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2); return updateForwardRef(current$$1, workInProgress, type, _resolvedProps2, renderExpirationTime); } case Fragment: return updateFragment(current$$1, workInProgress, renderExpirationTime); case Mode: return updateMode(current$$1, workInProgress, renderExpirationTime); case Profiler: return updateProfiler(current$$1, workInProgress, renderExpirationTime); case ContextProvider: return updateContextProvider(current$$1, workInProgress, renderExpirationTime); case ContextConsumer: return updateContextConsumer(current$$1, workInProgress, renderExpirationTime); case MemoComponent: { var _type2 = workInProgress.type; var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); { if (workInProgress.type !== workInProgress.elementType) { var outerPropTypes = _type2.propTypes; if (outerPropTypes) { checkPropTypes(outerPropTypes, _resolvedProps3, // Resolved for outer only 'prop', getComponentName(_type2), getCurrentFiberStackInDev); } } } _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); return updateMemoComponent(current$$1, workInProgress, _type2, _resolvedProps3, updateExpirationTime, renderExpirationTime); } case SimpleMemoComponent: { return updateSimpleMemoComponent(current$$1, workInProgress, workInProgress.type, workInProgress.pendingProps, updateExpirationTime, renderExpirationTime); } case IncompleteClassComponent: { var _Component3 = workInProgress.type; var _unresolvedProps4 = workInProgress.pendingProps; var _resolvedProps4 = workInProgress.elementType === _Component3 ? _unresolvedProps4 : resolveDefaultProps(_Component3, _unresolvedProps4); return mountIncompleteClassComponent(current$$1, workInProgress, _Component3, _resolvedProps4, renderExpirationTime); } case DehydratedSuspenseComponent: { if (enableSuspenseServerRenderer) { return updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime); } break; } }

1)mountIndeterminateComponent:
不确定的组件类型
IndeterminateComponent只有在组件被第一次渲染的情况下才会出现,在经过第一次渲染之后,
我们就会更新组件的类型,也就是Fiber.tag。如果出现了_current存在的情况,那么可能是因为渲染时有Suspend的情况

//对于ClassComponent和FunctionalComponent的判断条件
  if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
    workInProgress.tag = ClassComponent;
	
	...
	
  } else {
    workInProgress.tag = FunctionComponent;
    reconcileChildren(null, workInProgress, value, renderExpirationTime);
    return workInProgress.child;
  }

2)mountLazyComponent:
lazy组件只有在加载的组件还没完成之前才会被执行,等到加载完成了,那么就变成加载之后的组件了,永远不会执行到自己的更新

 //把lazy组件的Fiber对象的tag和type都改变了,下次执行到这个Fiber的更新,则会直接更新返回的type
  workInProgress.type = Component;
  var resolvedTag = workInProgress.tag = resolveLazyComponentTag(Component);

3)updateFunctionalComponent:
functionalComponent本身就是一个pure function,所以处理起来相对很简单,获得对应的props和context之后,直接调用就能获得nextChildren,然后就是常规操作reconcileChildren和memoizeProps。
4)updateClassComponent:
其中 constructClassInstance 有 var instance = new ctor(props, context); (所以自定义的class组件引入时候不需要手动new),执行 adoptClassInstance 这个方法给 ClassComponent 的实例挂载一个updater对象:

{
  enqueueForceUpdate: func,
  enqueueReplaceState: func,
  enqueueSetState: func,
  isMounted: func
}
function adoptClassInstance(workInProgress, instance) {
  instance.updater = classComponentUpdater
  workInProgress.stateNode = instance
  // The instance needs access to the fiber so that it can schedule updates
  set(instance, workInProgress)
}

function set(key, value) {
  key._reactInternalFiber = value
}

这里通过set给 instance 的_reactInternalFiber挂载上workInProgress,所以我们可以通过this._reactInternalFiber获取该实例对应的Fiber对象。
接下来执行 mountClassInstance:
初始化 props、state 等实例属性,如果有updateQueue就更新之,一般来说第一次渲染是没有的。

processUpdateQueue用来计算新的state

var getDerivedStateFromProps = workInProgress.type.getDerivedStateFromProps
if (typeof getDerivedStateFromProps === 'function') {
  applyDerivedStateFromProps(workInProgress, getDerivedStateFromProps, props)
  instance.state = workInProgress.memoizedState
}

如果 class 有声明getDerivedStateFromProps,就调用他,调用该方法之后会根据结果更新workInProgress.memoizedState,所以要重新赋值给instance.state

接下去判断一下是否没有新的生命周期方法,如果没有并且有componentWillMount生命周期方法,则调用他。

最后判断是否有componentDidMount,如果有就修改workInProgress.effectTag |= Update,因为componentDidMount要在真正渲染进DOM之后才调用,也就是commit之后。
5)updateHostRoot:
//会判断这个 fiber 的子树是否需要更新如果有需要更新会 clone 一份到 workInProgress.child 返回到 workLoop 的 nextUnitOfWork, 否则为 null

return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);

processUpdateQueue:

//计算更新 state
function processUpdateQueue(workInProgress, queue, props, instance, renderExpirationTime) {
  hasForceUpdate = false;
  //克隆一份 updateQueue进行更新
  queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);

  {
    currentlyProcessingQueue = queue;
  }

  // These values may change as we process the queue.
  var newBaseState = queue.baseState;  //每次执行完 processUpdateQueue 都会把新的 state 赋值到 queue.baseState
  var newFirstUpdate = null;
  var newExpirationTime = NoWork;

  // Iterate through the list of updates to compute the result.
  var update = queue.firstUpdate;  //链表起始
  var resultState = newBaseState;
  while (update !== null) {  //对每个update 执行 setState
    var updateExpirationTime = update.expirationTime;
    //低优先级 
    if (updateExpirationTime < renderExpirationTime) {
      // This update does not have sufficient priority. Skip it.
      if (newFirstUpdate === null) {
        // This is the first skipped update. It will be the first update in
        // the new list.
        newFirstUpdate = update;
        // Since this is the first update that was skipped, the current result
        // is the new base state.
        newBaseState = resultState;
      }
      // Since this update will remain in the list, update the remaining
      // expiration time.
      //等待下次更新
      if (newExpirationTime < updateExpirationTime) {
        newExpirationTime = updateExpirationTime;
      }
    } else {
      // This update does have sufficient priority. Process it and compute
      // a new result. 计算新的state结果
      resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance);
      //setState中第二个参数 callback
      var _callback = update.callback;
      if (_callback !== null) {
        workInProgress.effectTag |= Callback;
        // Set this to null, in case it was mutated during an aborted render.
        update.nextEffect = null;
        if (queue.lastEffect === null) {
          queue.firstEffect = queue.lastEffect = update;
        } else {
          queue.lastEffect.nextEffect = update;
          queue.lastEffect = update;
        }
      }
    }
    // Continue to the next update.  下个update
    update = update.next;
  }
  ...
}

getStateFromUpdate:
根据 update.tag 计算 state 的结果,会判断 setState 传入的函数或对象两种情况
1 函数时会指定上下文,传入 prevState, nextProps
2 对象时就是最终要更新的 state 对象
3 最后通过 Object.assign 生成新的 state 对象

case UpdateState:
      {
        var _payload2 = update.payload;
        var partialState = void 0;
        if (typeof _payload2 === 'function') {
          // Updater function
          partialState = _payload2.call(instance, prevState, nextProps);
          {
            exitDisallowedContextReadInDEV();
          }
        } else {
          // setState传入的是对象   直接返回
          partialState = _payload2;
        }
        if (partialState === null || partialState === undefined) {
          // Null and undefined are treated as no-ops.
          return prevState;
        }
        // _assign合并 state
        return _assign({}, prevState, partialState);
      }

6)updateHostComponent:
更新 HostComponent 原生 dom 标签
原生标签 小写的 标签
判断标签内容是不是纯文本
是纯文本没子节点,不是纯文本根据之前的 props 标记更新
跟 classCompnent 一样有 makeRef 能使用 ref
接下篇…

你可能感兴趣的:(js,react,react源码)