#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'
// }
相信有了前置知识,代码看起来不那么费力了。
在React源码中,构造函数的使用:通常以"create"关键字命名的函数,函数返回一个构造函数实例或者嵌套调用一个"create"关键字命名的函数进行嵌套调用。
CreateRoot方法比较复杂,我列举出了重要"create"关键词的五种。
这是createRoot过程中完整的函数调用栈,嵌套调用了多种函数:
其中:
接收(container, options),返回对应React中虚拟DOM对象,其中:
//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);
}
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);
}
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;
}
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);
}
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);
};