请参考:
https://github.com/a8397550/react-source-share.git

行数
https://github.com/a8397550/react-source-share/blob/master/default/react-dom-default.js

下面源码分析建立在以下HTML的代码的基础上

  1. <!-- /dist/index.html -->
  2. <!doctype html>
  3. <html>
  4. <head>
  5. <title>react</title>
  6. <script src="./react.js"></script>
  7. <script src="./react-dom.js"></script>
  8. <style>
  9. .classA {
  10. color: red;
  11. }
  12. .classA .classB {
  13. color: blue;
  14. }
  15. </style>
  16. </head>
  17. <body>
  18. <div id="root"><div></div>
  19. </div>
  20. <script>
  21. console.log("React", React);
  22. console.log("ReactDOM", ReactDOM);
  23. var DivSon = React.createElement("div", { className: 'classB', onClick: function(){ alert("点击事件哦") } }, "777");
  24. var DivSonA = React.createElement("span", { className: 'classC' }, "这里是一个span");
  25. // props.children
  26. // ref的使用
  27. // setState如何触发
  28. var Div = React.createElement("div", { className: 'classA' }, DivSon, 999, DivSonA);
  29. ReactDOM.render(Div, document.getElementById('root'));
  30. </script>
  31. </body>
  32. </html>

Render 初始化分析

render: function (element, container, callback)

源码所在行数 25156

(function () {
  // 自执行函数,验证container是一个DOM元素
  var isValid = isValidContainer(container);
  if (!isValid) {
    {
      throw ReactError(Error('Target container is not a DOM element.'));
    }
  }
})();

/**  
* node存在 && node.nodeType === 1 返回true
* node存在 && node.nodeType === 9 返回true
* node存在 && node.nodeType === 11 返回true
* node存在 && node.nodeType === 8 && node.nodeValue === ' react-mount-point-unstable ' 
*   返回true
* 其他情况返回 false
* 此处的 && || 的用法
* && 的用法是 前面的结果为true 就使用后面的结果
* || 的用法是 前面的结果是false 就使用后面的结果
*/
function isValidContainer(node) {
  return !!(node && (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE || node.nodeType === COMMENT_NODE && node.nodeValue === ' react-mount-point-unstable '));
}
{
  // 验证DOM元素,是否已经被绑定ReactDOM绑定过
  // 如果DOM元素是已被ReactDOM.render过的元素的话,给出警告,否则继续执行下面的代码
  !!container._reactHasBeenPassedToCreateRootDEV ? warningWithoutStack$1(false, 'You are calling ReactDOM.Render() on a container that was previously ' + 'passed to ReactDOM.%s(). This is not supported. ' + 'Did you mean to call root.Render(element)?', enableStableConcurrentModeAPIs ? 'createRoot' : 'unstable_createRoot') : void 0;
}

源码所在行数 25167

return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);

function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback)

源码所在行数 25086
container._reactRootContainer
container.firstChild[internalInstanceKey]

{
      // 验证container有没有被react初始化过,
    // 或者container的第一个子元素有没有被初始化过,
    // 或者有没有使用document.body作为容器,
    // 满足上面条件的话,给出对应的警告
    topLevelUpdateWarnings(container);
    warnOnInvalidCallback = function (callback, callerName) {
      !(callback === null || typeof callback === 'function') ? warningWithoutStack$1(false, '%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback) : void 0;
    };
    // callback 如果不是null 也不是一个function的话,给出警告
    warnOnInvalidCallback(callback === undefined ? null : callback, 'render');
}

topLevelUpdateWarnings = function (container) {
  if (container._reactRootContainer && container.nodeType !== COMMENT_NODE) {
    // 进入if的条件时container._reactRootContainer存在并且container不是一个注释,而是一个元素
    var hostInstance = findHostInstanceWithNoPortals(container._reactRootContainer._internalRoot.current);
    if (hostInstance) {
      !(hostInstance.parentNode === container) ? warningWithoutStack$1(false, 'Render(...): It looks like the React-rendered content of this ' + 'container was removed without using React. This is not ' + 'supported and will cause errors. Instead, call ' + 'ReactDOM.unmountComponentAtNode to empty a container.') : void 0;
    }
  }
    // 初始化时值为false
  var isRootRenderedBySomeReact = !!container._reactRootContainer;
  // 获取container元素节点下的第一个子节点
  function getReactRootElementInContainer(container) {
    if (!container) {
      return null;
    }

    if (container.nodeType === DOCUMENT_NODE) {
      return container.documentElement;
    } else {
      return container.firstChild;
    }
  }
  // 如果当前节点<div></div> 此时rootEl值为null
  // 如果当前节点<div> </div> 此时rootEl值为#text类型节点
  // 如果当前节点<div><div></div></div> 此时rootEl值为div节点
  var rootEl = getReactRootElementInContainer(container);
  function getInstanceFromNode$1(node) {
    // internalInstanceKey 是一个常量,在react-dom被加载时初始化
    // '__reactInternalInstance$' + Math.random().toString(36).slice(2);
    // 假设internalInstanceKey当前值是"__reactInternalInstance$q0avznii6gi"
    var inst = node[internalInstanceKey];
    // 初始化时inst值为undefined;
    if (inst) {
      if (inst.tag === HostComponent || inst.tag === HostText) {
        return inst;
      } else {
        return null;
      }
    }
    return null;
  }
  // 验证node具备不具备"internalInstanceKey"属性,初始化时,node是没有那个属性的
  // 初始化时此值为false
  var hasNonRootReactChild = !!(rootEl && getInstanceFromNode$1(rootEl));
    // 初始化时 !(!false || false) 结果为 false
  // 当三元表达式值为true时,给出警告
  !(!hasNonRootReactChild || isRootRenderedBySomeReact) ? warningWithoutStack$1(false, 'Render(...): Replacing React-rendered children with a new root ' + 'component. If you intended to update the children of this node, ' + 'you should instead have the existing children update their state ' + 'and Render the new components instead of calling ReactDOM.Render.') : void 0;
    // 满足3个false的条件, 给出警告
  // container.nodeType === 1
  // container.tagName 存在
  // container.tagName.toUpperCase() === 'BODY'
  // 作者的用意大概是说,如果你使用document.body做容器的话,会给你一个警告
  !(container.nodeType !== ELEMENT_NODE || !container.tagName || container.tagName.toUpperCase() !== 'BODY') ? warningWithoutStack$1(false, 'Render(): Rendering components directly into document.body is ' + 'discouraged, since its children are often manipulated by third-party ' + 'scripts and browser extensions. This may lead to subtle ' + 'reconciliation issues. Try rendering into a container element created ' + 'for your app.') : void 0;
};
// 默认的时候 undefined
var root = container._reactRootContainer; 
// fiber [faɪbə] 构造的意思
var fiberRoot = void 0;

if (!root) {
  root = container._reactRootContainer = 
    legacyCreateRootFromDOMContainer(container, forceHydrate);
  // ...
} else {
  // ...
}

function legacyCreateRootFromDOMContainer(container, forceHydrate)

此方法会返回一个ReactSyncRoot的实例对象

function legacyCreateRootFromDOMContainer(container, forceHydrate) {
  function shouldHydrateDueToLegacyHeuristic(container) {
    function getReactRootElementInContainer(container) {
          if (!container) {
            return null;
          }

          if (container.nodeType === DOCUMENT_NODE) {
            return container.documentElement;
          } else {
            return container.firstChild;
          }
    }
    var rootElement = getReactRootElementInContainer(container);
    // 子元素存在
    // 并且类型 nodeType = 1
    // 并且hasAttribute('data-reactroot') 存在
    // hasAttribute是DOM的方法,可以验证他的属性存在不存在
    return !!(rootElement && rootElement.nodeType === ELEMENT_NODE && rootElement.hasAttribute(ROOT_ATTRIBUTE_NAME));
  }
  // 初始化时 forceHydrate = false
    var shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
  // 在以下状态时不执行
  // container首个子元素存在并且nodeType = 1,并且此子元素"data-reactroot"属性存在
  if (!shouldHydrate) {
    // 删除container下所有子节点
    var warned = false;
    var rootSibling = void 0;
    while (rootSibling = container.lastChild) {
      {
        // 首次发现子节点的nodeType = 1,并且具备"data-reactroot"属性,给出警告
        if (!warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) {
          warned = true;
          warningWithoutStack$1(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);
    }
  }

  {
    // 满足某个条件,给出提示,暂不分析
    // 此处可能和react的ssr(服务端渲染 server side render)有关
    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.');
    }
  }
  // LegacyRoot 默认是0 shouldHydrate 是一个boolean值
  // LegacyRoot 是一个全局变量
  // 此时假设 shouldHydrate = false;
  return new ReactSyncRoot(container, LegacyRoot, shouldHydrate);
}

ReactSyncRoot 实例
this._internalRoot = new fiberRootNode
this._internalRoot.current = new FiberNode(…)
this._internalRoot.current.stateNode = this._internalRoot;

/**
* @description 构造对象 ReactSyncRoot
* @param {HTMLElement} container 
* @param {number} tag 最初是0
* @param {boolean} hydrate 
* this._internalRoot = new fiberRootNode
*/
function ReactSyncRoot(container, tag, hydrate) {
  var root = createFiberRoot(container, tag, hydrate);
  this._internalRoot = root;
}

function createFiberRoot(containerInfo, tag, hydrate) {
  var root = new FiberRootNode(containerInfo, tag, hydrate);
  // uninitializedFiber [ˌʌnɪˈnɪʃəˌlaɪzd] 未初始化
  // initializedFiber [ɪˈnɪʃəlaɪzd] 已初始化
  var uninitializedFiber = createHostRootFiber(tag);
  root.current = uninitializedFiber;
  uninitializedFiber.stateNode = root;

  return root;
}

function FiberRootNode(containerInfo, tag, hydrate) {
  this.tag = tag;
  this.current = null;
  this.containerInfo = containerInfo;
  this.pendingChildren = null;
  this.pingCache = null;
  // 全局变量,初始化时为 0
  this.finishedExpirationTime = NoWork;
  this.finishedWork = null;
  // 全局变量初始为 -1
  this.timeoutHandle = noTimeout;
  this.context = null;
  this.pendingContext = null;
  this.hydrate = hydrate;
  this.firstBatch = null;
  this.callbackNode = null;
  this.callbackExpirationTime = NoWork;
  this.firstPendingTime = NoWork;
  this.lastPendingTime = NoWork;
  this.pingTime = NoWork;
    // 全局变量
  if (enableSchedulerTracing) {
    // 全局方法 unstable_getThreadID
    // 注意,它的出处在React源码中
    /*
        function unstable_getThreadID () {
          // threadIDCounter 初始值为0
        return ++threadIDCounter;
      }
    */
    this.interactionThreadID = unstable_getThreadID();
    this.memoizedInteractions = new Set();
    this.pendingInteractionMap = new Map();
  }
}

function createHostRootFiber(tag) {
  var mode = void 0;
  // 常量 ConcurrentRoot = 2
  if (tag === ConcurrentRoot) {
    // ConcurrentMode 常量4
    // BatchedMode 常量 2
    // StrictMode 常量 1
    // ConcurrentMode | BatchedMode | StrictMode 值等于 7
    // 注意 这里是位运算
    mode = ConcurrentMode | BatchedMode | StrictMode;
  } else if (tag === BatchedRoot) {
    // 注意 这里是位运算
    mode = BatchedMode | StrictMode;
  } else {
    // 初始化时,NoMode值为0
    mode = NoMode;
  }
    // 初始化时 enableProfilerTimer = true && isDevToolsPresent = false
  if (enableProfilerTimer && isDevToolsPresent) {
    // ProfileMode 常量值 8
    mode |= ProfileMode;
  }

  var createFiber = function (tag, pendingProps, key, mode) {
    return new FiberNode(tag, pendingProps, key, mode);
  };
  // HostRoot 全局常量 常量值3
  return createFiber(HostRoot, null, null, mode);
}

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

  // Fiber
  this.return = null; // 父元素
  this.child = null; // [tʃaɪld] 子元素
  this.sibling = null; // [ˈsɪblɪŋ] 下一个元素
  this.index = 0;

  this.ref = null;

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

  this.mode = mode;

  // Effects
  // 当前DIFF类型 默认0 ,4 update,8 Deletion,2 Placement,6 PlacementAndUpdate
  this.effectTag = NoEffect;
  // 要修改的FiberNode链
  this.nextEffect = null;

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

  this.expirationTime = NoWork;
  this.childExpirationTime = NoWork;

  this.alternate = null;

  if (enableProfilerTimer) {
    // Note: The following is done to avoid a v8 performance cliff.
    //
    // Initializing the fields below to smis and later updating them with
    // double values will cause Fibers to end up having separate shapes.
    // This behavior/bug has something to do with Object.preventExtension().
    // Fortunately this only impacts DEV builds.
    // Unfortunately it makes React unusably slow for some applications.
    // To work around this, initialize the fields below with doubles.
    //
    // Learn more about this here:
    // https://github.com/facebook/react/issues/14365
    // https://bugs.chromium.org/p/v8/issues/detail?id=8538
    this.actualDuration = Number.NaN;
    this.actualStartTime = Number.NaN;
    this.selfBaseDuration = Number.NaN;
    this.treeBaseDuration = Number.NaN;

    // It's okay to replace the initial doubles with smis after initialization.
    // This won't trigger the performance cliff mentioned above,
    // and it simplifies other profiler code (including DevTools).
    this.actualDuration = 0;
    this.actualStartTime = -1;
    this.selfBaseDuration = 0;
    this.treeBaseDuration = 0;
  }

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