React源码2 React中的工厂函数:createRoot()

#React V18.2 源码

前置基础知识:工厂函数

工厂函数是一种设计模式,用于动态创建对象或函数实例。其核心思想是通过封装对象创建的细节,提供统一的接口,从而增强代码的灵活性和可维护性,有一些核心作用:

  • 解耦创建逻辑:将对象的实例化过程与使用分离,调用方无需关心具体实现细节。
  • 动态生成:根据输入参数返回不同类型的对象或函数。
  • 统一接口:通过单一入口点管理多种创建场景。

工厂函数由构造函数进阶而来,都是用来创建实例。

这是一个函数,KindofNode“某类节点”的构造函数,可以通过new,创建一个实例对象(开辟一块空间,将原型拷贝到该空间,并将该空间的this指向该实例)。很好理解。

function KindOfNode(kind, properties1, properties2, properties3) {
	//这是一个构造函数
	this.kind = kind;
	this.properties1 = properties1;
	this.properties2 = properties2;
	this.properties3 = properties3;
}

aNode = new KindOfNode(null, '属性1', '属性2', '属性3'); //创建一个对象

console.dir(aNode);
//kindOfNode {
//   kind: null,
//   properties1: '属性1',
//   properties2: '属性2',
//   properties3: '属性3'
// }

create关键词函数,在框架中约定俗成为构造函数(博主观察发现),让我们对这个构造函数进行改进,可以发现可以选择性的对构造出来的实例某些属性进行赋值。


    function createNode(kind, properties1, properties2, properties3) {
    	//这是一个工厂函数
    
    	const node = new KindOfNode(kind, properties1, properties2, properties3);
    
    	if (kind === null || kind === undefined) {
    		node.kind = 'node';
    	}
    
    	if (kind === 'hostFiber') {
    		node.kind = 'hostFiber';
    	}
    
    	return node;
    }
    
    fa_node = createNode('hostFiber', '属性1', '属性2', '属性3'); //创建一个对象
    fb_node = createNode(null, '属性1', '属性2', '属性3'); //创建一个对象
    
    console.dir(fa_node);
    console.dir(fb_node);
    // kindOfNode {
    //   kind: 'hostFiber',
    //   properties1: '属性1',
    //   properties2: '属性2',
    //   properties3: '属性3'
    // }
    // kindOfNode {
    //   kind: 'node',
    //   properties1: '属性1',
    //   properties2: '属性2',
    //   properties3: '属性3'
    // }

    让我们正式进入createRoot()方法

    相信有了前置知识,代码看起来不那么费力了。

    在React源码中,构造函数的使用:通常以"create"关键字命名的函数,函数返回一个构造函数实例或者嵌套调用一个"create"关键字命名的函数进行嵌套调用

    CreateRoot方法比较复杂,我列举出了重要"create"关键词的五种。

    这是createRoot过程中完整的函数调用栈,嵌套调用了多种函数:

    React源码2 React中的工厂函数:createRoot()_第1张图片

    其中:

    • exports.createRoot是在node.js中遵循CommanJS标准的包导出。
    • createRoot$1,出于安全性添加的一层。
    • createRoot➡️createFiber,依此进行react初始化创建。
    • FiberNode构造函数是push进栈最后一个栈帧,运行完后将从上到下依次pop出栈。

    一、createRoot()

    接收(container, options),返回对应React中虚拟DOM对象,其中:

    • container:其中我们在index.html入口文件选择的真实DOM根节点。
    • options:用于配置这个 React 根节点的对象。(基本用不到这个参数吧)
    //createRoot()
    function createRoot(container, options) {
      if (!isValidContainer(container)) {
        throw new Error('createRoot(...): Target container is not a DOM element.');
      }
    
      warnIfReactDOMContainerInDEV(container);
      var isStrictMode = false;
      var concurrentUpdatesByDefaultOverride = false;
      var identifierPrefix = '';
      var onRecoverableError = defaultOnRecoverableError;
      var transitionCallbacks = null;
    
      if (options !== null && options !== undefined) {
        {
          if (options.hydrate) {
            warn('hydrate through createRoot is deprecated. Use ReactDOMClient.hydrateRoot(container, ) instead.');
          } else {
            if (typeof options === 'object' && options !== null && options.$$typeof === REACT_ELEMENT_TYPE) {
              error('You passed a JSX element to createRoot. You probably meant to ' + 'call root.render instead. ' + 'Example usage:\n\n' + '  let root = createRoot(domContainer);\n' + '  root.render();');
            }
          }
        }
    
        if (options.unstable_strictMode === true) {
          isStrictMode = true;
        }
    
        if (options.identifierPrefix !== undefined) {
          identifierPrefix = options.identifierPrefix;
        }
    
        if (options.onRecoverableError !== undefined) {
          onRecoverableError = options.onRecoverableError;
        }
    
        if (options.transitionCallbacks !== undefined) {
          transitionCallbacks = options.transitionCallbacks;
        }
      }
    
      var root = createContainer(container, ConcurrentRoot, null, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError);
      markContainerAsRoot(root.current, container);
      var rootContainerElement = container.nodeType === COMMENT_NODE ? container.parentNode : container;
      listenToAllSupportedEvents(rootContainerElement);
      return new ReactDOMRoot(root);
    }

    二、createContainer()

    function createContainer(containerInfo, tag, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError, transitionCallbacks) {
      var hydrate = false;
      var initialChildren = null;
      return createFiberRoot(containerInfo, tag, hydrate, initialChildren, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError);
    }

    三、createFiberRoot()

    function createFiberRoot(containerInfo, tag, hydrate, initialChildren, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, // TODO: We have several of these arguments that are conceptually part of the
    // host config, but because they are passed in at runtime, we have to thread
    // them through the root constructor. Perhaps we should put them all into a
    // single type, like a DynamicHostConfig that is defined by the renderer.
    identifierPrefix, onRecoverableError, transitionCallbacks) {
      var root = new FiberRootNode(containerInfo, tag, hydrate, identifierPrefix, onRecoverableError);
      // stateNode is any.
    
    
      var uninitializedFiber = createHostRootFiber(tag, isStrictMode);
      root.current = uninitializedFiber;
      uninitializedFiber.stateNode = root;
    
      {
        var _initialState = {
          element: initialChildren,
          isDehydrated: hydrate,
          cache: null,
          // not enabled yet
          transitions: null,
          pendingSuspenseBoundaries: null
        };
        uninitializedFiber.memoizedState = _initialState;
      }
    
      initializeUpdateQueue(uninitializedFiber);
      return root;
    }

    四、createHostRootFiber()

    function createHostRootFiber(tag, isStrictMode, concurrentUpdatesByDefaultOverride) {
      var mode;
    
      if (tag === ConcurrentRoot) {
        mode = ConcurrentMode;
    
        if (isStrictMode === true) {
          mode |= StrictLegacyMode;
    
          {
            mode |= StrictEffectsMode;
          }
        }
      } else {
        mode = NoMode;
      }
    
      if ( isDevToolsPresent) {
        // Always collect profile timings when DevTools are present.
        // This enables DevTools to start capturing timing at any point–
        // Without some nodes in the tree having empty base times.
        mode |= ProfileMode;
      }
    
      return createFiber(HostRoot, null, null, mode);
    }

    五、creteFiber()

    var createFiber = function (tag, pendingProps, key, mode) {
      // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors
      return new FiberNode(tag, pendingProps, key, mode);
    };

    你可能感兴趣的:(ReactV18.2源码,react.js,javascript,前端)