Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React 16 架构学习资料 #10

Open
Foveluy opened this issue May 13, 2018 · 4 comments
Open

React 16 架构学习资料 #10

Foveluy opened this issue May 13, 2018 · 4 comments
Labels
Article for building article

Comments

@Foveluy Foveluy added the Article for building article label May 13, 2018
@Foveluy
Copy link
Owner Author

Foveluy commented May 13, 2018

fiber tag

export type TypeOfWork = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;

export const IndeterminateComponent = 0; // 尚不知是类组件还是函数式组件
export const FunctionalComponent = 1; // 函数式组件
export const ClassComponent = 2; // Class类组件
export const HostRoot = 3; // 组件树根组件,可以嵌套
export const HostPortal = 4; // 子树. Could be an entry point to a different renderer.
export const HostComponent = 5; // 标准组件,如地div, span等
export const HostText = 6; // 文本
export const CallComponent = 7; // 组件调用
export const CallHandlerPhase = 8; // 调用组件方法
export const ReturnComponent = 9; // placeholder(占位符)
export const Fragment = 10; // 片段

@Foveluy
Copy link
Owner Author

Foveluy commented May 15, 2018

  • legacyCreateRootFromDOMContainer
// A Fiber is work on a Component that needs to be done or was done. There can
// be more than one per component.


var debugCounter = void 0;

{
  debugCounter = 1;
}

function FiberNode(tag, pendingProps, key, mode) {
  // Instance
  this.tag = tag;
  this.key = key;
  this.type = null;
  this.stateNode = null;

  // Fiber
  this['return'] = null;
  this.child = null;
  this.sibling = null;
  this.index = 0;

  this.ref = null;

  this.pendingProps = pendingProps;
  this.memoizedProps = null;
  this.updateQueue = null;
  this.memoizedState = null;

  this.mode = mode;

  // Effects
  this.effectTag = NoEffect;
  this.nextEffect = null;

  this.firstEffect = null;
  this.lastEffect = null;

  this.expirationTime = NoWork;

  this.alternate = null;

  {
    this._debugID = debugCounter++;
    this._debugSource = null;
    this._debugOwner = null;
    this._debugIsCurrentlyTiming = false;
    if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
      Object.preventExtensions(this);
    }
  }
}

@Foveluy
Copy link
Owner Author

Foveluy commented May 15, 2018

render
|
v
legacyCreateRootFromDOMContainer
//这个函数会给 root container 创建一个 Root.fiber 和是一个特殊的对象
function legacyCreateRootFromDOMContainer(container, forceHydrate) {
  var shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
  // First clear any existing content.
  if (!shouldHydrate) {
    var warned = false;
    var rootSibling = void 0;
    while (rootSibling = container.lastChild) {
      {
        if (!warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) {
          warned = true;
          warning(false, 'render(): Target node has markup rendered by React, but there ' + 'are unrelated nodes as well. This is most commonly caused by ' + 'white-space inserted around server-rendered markup.');
        }
      }
      container.removeChild(rootSibling);
    }
  }
  {
    if (shouldHydrate && !forceHydrate && !warnedAboutHydrateAPI) {
      warnedAboutHydrateAPI = true;
      lowPriorityWarning$1(false, 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' + 'will stop working in React v17. Replace the ReactDOM.render() call ' + 'with ReactDOM.hydrate() if you want React to attach to the server HTML.');
    }
  }
  // Legacy roots are not async by default.
  var isAsync = false;
  return new ReactRoot(container, isAsync, shouldHydrate);
}
// 那么 fiber root 的结构是
function createFiberRoot(containerInfo, isAsync, hydrate) {
  // Cyclic construction. This cheats the type system right now because
  // stateNode is any.
  var uninitializedFiber = createHostRootFiber(isAsync);
  var root = {
    current: uninitializedFiber,
    containerInfo: containerInfo,
    pendingChildren: null,
    pendingCommitExpirationTime: NoWork,
    finishedWork: null,
    context: null,
    pendingContext: null,
    hydrate: hydrate,
    remainingExpirationTime: NoWork,
    firstBatch: null,
    nextScheduledRoot: null
  };
  uninitializedFiber.stateNode = root;
  return root;
}

|
|
v

//首次渲染不会执行批量更新
DOMRenderer.unbatchedUpdates
|
v
updateContainer
|
v
//获取context
  var context = getContextForSubtree(parentComponent);
    if (container.context === null) {
      container.context = context;
    } else {
      container.pendingContext = context;
    }
|
v
scheduleRootUpdate()
//伴随着以下数据结构
 var update = {
      expirationTime: expirationTime,
      partialState: { element: element },
      callback: callback,
      isReplace: false,
      isForced: false,
      capturedValue: null,
      next: null
    };
|
v
insertUpdateIntoFiber()
 // 这个函数做了一件事情
// setState 和 render 的时候,都会创建一个 update,这个方法就是把这个 update 放入队列中,这个队列是一个链表
|
v
//是执行虚拟DOM(fiber树)的更新
scheduleWorkImpl() --->scheduleWork是他的包囊方法,其实没啥用
|
v
// Add this root to the root schedule.
requestWork(root, expirationTime);
|
v
// 调用 performSyncWork()
 if (expirationTime === Sync) {
      performSyncWork();
    } else {
      scheduleCallbackWithExpiration(expirationTime);
}
|
v
// performWork(Sync, false, null);
performWork(Sync, false, null);
|
v
performWorkOnRoot()
|
v
//往下走到达 
renderRoot(root, expirationTime, isAsync)
//再往下就是一个关键的方法,这个方法中,我们通过现有的 Fiber 构建出 
// WorkInProgress tree,WorkInProgress tree 就是新的 Fiber
// 对其进行比较
function createWorkInProgress(current, pendingProps, expirationTime)
// This is used to create an alternate fiber to do work on.
|
v
workloop
|
|
v
performUnitOfWork(workInProgress)
|
|
v
//这个方法,返回下一个要处理的 Fiber
function beginWork(current, workInProgress, renderExpirationTime) 
// 这个函数是一个 switch tag.
  switch (workInProgress.tag) {
      case IndeterminateComponent:
        return mountIndeterminateComponent(current, workInProgress, renderExpirationTime);
      case FunctionalComponent:
        return updateFunctionalComponent(current, workInProgress);
      case ClassComponent:
        return updateClassComponent(current, workInProgress, renderExpirationTime);
      case HostRoot:
        return updateHostRoot(current, workInProgress, renderExpirationTime);
      case HostComponent:
        return updateHostComponent(current, workInProgress, renderExpirationTime);
      case HostText:
        return updateHostText(current, workInProgress);
      case CallHandlerPhase:
        // This is a restart. Reset the tag to the initial phase.
        workInProgress.tag = CallComponent;
      // Intentionally fall through since this is now the same.
      case CallComponent:
        return updateCallComponent(current, workInProgress, renderExpirationTime);
      case ReturnComponent:
        // A return component is just a placeholder, we can just run through the
        // next one immediately.
        return null;
      case HostPortal:
        return updatePortalComponent(current, workInProgress, renderExpirationTime);
      case ForwardRef:
        return updateForwardRef(current, workInProgress);
      case Fragment:
        return updateFragment(current, workInProgress);
      case Mode:
        return updateMode(current, workInProgress);
      case ContextProvider:
        return updateContextProvider(current, workInProgress, renderExpirationTime);
      case ContextConsumer:
        return updateContextConsumer(current, workInProgress, renderExpirationTime);
      default:
        invariant(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.');
    }
  }
|
|
v
workInProgress.tag 是什么?
https://github.com/facebook/react/blob/master/packages/shared/ReactTypeOfWork.js
|
|
v
//核心方法
 function reconcileChildren(current, workInProgress, nextChildren)
|
|
v

// We've completed the root. Commit it.
completeRoot(root, finishedWork, expirationTime);
|
v
 // Commit the root.
root.finishedWork = null;
root.remainingExpirationTime = commitRoot(finishedWork);
|
v
//commitRoot() 巨复杂
|
v
commitLifeCycles()

//是一个大循环,拿到 effect list 进行循环

while (nextEffect !== null) {
      var effectTag = nextEffect.effectTag;

      if (effectTag & (Update | Callback)) {
        recordEffect();
        var current = nextEffect.alternate;
        commitLifeCycles(finishedRoot, current, nextEffect, currentTime, committedExpirationTime);
      }

      if (effectTag & ErrLog) {
        commitErrorLogging(nextEffect, onUncaughtError);
      }

      if (effectTag & Ref) {
        recordEffect();
        commitAttachRef(nextEffect);
      }

      var next = nextEffect.nextEffect;
      // Ensure that we clean these up so that we don't accidentally keep them.
      // I'm not actually sure this matters because we can't reset firstEffect
      // and lastEffect since they're on every node, not just the effectful
      // ones. So we have to clean everything as we reuse nodes anyway.
      nextEffect.nextEffect = null;
      // Ensure that we reset the effectTag here so that we can rely on effect
      // tags to reason about the current life-cycle.
      nextEffect = next;
    }
|
v

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Article for building article
Projects
None yet
Development

No branches or pull requests

1 participant