标签:ras empty oal with hand poi tables rop calling
React 源码分析~初次渲染
一、下载源码到本地
二、Render 为 入口
1. 导出 render
packages/react-dom/src/client/ReactDOM.js
import {
findDOMNode,
render,
hydrate,
unstable_renderSubtreeIntoContainer,
unmountComponentAtNode,
} from ‘./ReactDOMLegacy‘;
export {
createPortal,
batchedUpdates as unstable_batchedUpdates,
flushSync,
Internals as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
ReactVersion as version,
// Disabled behind disableLegacyReactDOMAPIs
findDOMNode,
hydrate,
render, // 此处导出
unmountComponentAtNode,
// exposeConcurrentModeAPIs
createRoot,
flushControlled as unstable_flushControlled,
scheduleHydration as unstable_scheduleHydration,
// Disabled behind disableUnstableRenderSubtreeIntoContainer
renderSubtreeIntoContainer as unstable_renderSubtreeIntoContainer,
// enableCreateEventHandleAPI
createEventHandle as unstable_createEventHandle,
// TODO: Remove this once callers migrate to alternatives.
// This should only be used by React internals.
runWithPriority as unstable_runWithPriority,
};
2. 当初始化渲染时,删除 container 内其他额外的元素,并在 root 上挂载 _internalRoot
packages/react-dom/src/client/ReactDOMLegacy.js
import {
findHostInstanceWithNoPortals,
updateContainer,
unbatchedUpdates,
getPublicRootInstance,
findHostInstance,
findHostInstanceWithWarning,
} from ‘react-reconciler/src/ReactFiberReconciler‘;
export function render(
element: React$Element<any>,
container: Container,
callback: ?Function,
) {
invariant(
isValidContainer(container),
‘Target container is not a DOM element.‘,
);
if (__DEV__) {
const isModernRoot =
isContainerMarkedAsRoot(container) &&
container._reactRootContainer === undefined;
if (isModernRoot) {
console.error(
‘You are calling ReactDOM.render() on a container that was previously ‘ +
‘passed to ReactDOM.createRoot(). This is not supported. ‘ +
‘Did you mean to call root.render(element)?‘,
);
}
}
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
}
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>,
children: ReactNodeList,
container: Container,
forceHydrate: boolean,
callback: ?Function,
) {
if (__DEV__) {
topLevelUpdateWarnings(container);
warnOnInvalidCallback(callback === undefined ? null : callback, ‘render‘);
}
let root = container._reactRootContainer;
let fiberRoot: FiberRoot;
if (!root) {
// Initial mount
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
container,
forceHydrate,
);
}
}
/**
* 当初始化渲染时,删除 container 内其他额外的元素
*/
function legacyCreateRootFromDOMContainer(
container: Container,
forceHydrate: boolean,
): RootType {
// First clear any existing content.
if (!forceHydrate) {
let rootSibling;
while ((rootSibling = container.lastChild)) {
container.removeChild(rootSibling);
}
}
return createLegacyRoot(
container,
forceHydrate
? {
hydrate: true,
}
: undefined,
);
}
3. FirberRoot 对象,RootFirber 对象创建的过程
packages/react-dom/src/client/ReactDOMRoot.js
export function createLegacyRoot(
container: Container,
options?: RootOptions,
): RootType {
return new ReactDOMLegacyRoot(container, options);
}
function ReactDOMLegacyRoot(container: Container, options: void | RootOptions) {
this._internalRoot = createRootImpl(container, LegacyRoot, options);
}
/**
* 创建 FirberRoot 对象
* 并在 FirberRoot 上挂载 rootFirber
* 并将其返回到 _internalRoot 对象上,此时 _internalRoot = FirberRoot
*/
function createRootImpl(
container: Container,
tag: RootTag,
options: void | RootOptions,
) {
// Tag is either LegacyRoot or Concurrent Root
const hydrate = options != null && options.hydrate === true;
const hydrationCallbacks =
(options != null && options.hydrationOptions) || null;
const mutableSources =
(options != null &&
options.hydrationOptions != null &&
options.hydrationOptions.mutableSources) ||
null;
const isStrictMode = options != null && options.unstable_strictMode === true;
let concurrentUpdatesByDefaultOverride = null;
if (allowConcurrentByDefault) {
concurrentUpdatesByDefaultOverride =
options != null && options.unstable_concurrentUpdatesByDefault != null
? options.unstable_concurrentUpdatesByDefault
: null;
}
// 将 id="root" 转化为 Firber 对象
const root = createContainer(
container,
tag,
hydrate,
hydrationCallbacks,
isStrictMode,
concurrentUpdatesByDefaultOverride,
);
// 重新 node[__reactContainer] = #idrootFirber
markContainerAsRoot(root.current, container);
const rootContainerElement =
container.nodeType === COMMENT_NODE ? container.parentNode : container;
listenToAllSupportedEvents(rootContainerElement);
if (mutableSources) {
for (let i = 0; i < mutableSources.length; i++) {
const mutableSource = mutableSources[i];
registerMutableSourceForHydration(root, mutableSource);
}
}
return root;
}
4. 选择 创建Firber 的方式?
packages/react-reconciler/src/ReactFiberReconciler.js
import { createContainer as createContainer_old, getCurrentUpdatePriority as getCurrentUpdatePriority_old, } from ‘./ReactFiberReconciler.old‘; import { createContainer as createContainer_new, } from ‘./ReactFiberReconciler.new‘; export const createContainer = enableNewReconciler ? createContainer_new : createContainer_old;
5. createContainer_old 创建 Firber 的方式( 此处为重点的重点,包括React的重点流程在此处,可多次反复查看代码 )
import { createFiberRoot } from ‘./ReactFiberRoot.old‘;
export function createContainer(
containerInfo: Container,
tag: RootTag,
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
isStrictMode: boolean,
concurrentUpdatesByDefaultOverride: null | boolean,
): OpaqueRoot {
return createFiberRoot(
containerInfo,
tag,
hydrate,
hydrationCallbacks,
isStrictMode,
concurrentUpdatesByDefaultOverride,
);
}
/**
* 1. 创建 FiberRoot
* 2. 创建 RootFiber
* 3. 在 Fiber.current 上挂载 RootFiber
* 4. 在 RootFiber.stateNode 挂载 FiberRoot
* 5. 初始化队列: 在 RootFiber 上挂载 updateQueue
*/
export function createFiberRoot(
containerInfo: any,
tag: RootTag,
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
isStrictMode: boolean,
concurrentUpdatesByDefaultOverride: null | boolean,
): FiberRoot {
const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
if (enableSuspenseCallback) {
root.hydrationCallbacks = hydrationCallbacks;
}
// Cyclic construction. This cheats the type system right now because
// stateNode is any.
// 创建 RootFiber
const uninitializedFiber = createHostRootFiber(
tag,
isStrictMode,
concurrentUpdatesByDefaultOverride,
);
// 在 Fiber.current 上挂载 RootFiber
root.current = uninitializedFiber;
// 在 RootFiber.stateNode 挂载 FiberRoot
uninitializedFiber.stateNode = root;
if (enableCache) {
const initialCache = new Map();
root.pooledCache = initialCache;
const initialState = {
element: null,
cache: initialCache,
};
uninitializedFiber.memoizedState = initialState;
} else {
const initialState = {
element: null,
};
uninitializedFiber.memoizedState = initialState;
}
// 初始化更新队列
initializeUpdateQueue(uninitializedFiber);
return root;
}
6. 初次创建 RootFiber(此处是)
/**
* 创建 RootFiber,并返回 Firber
* tag = 0
*/
export function createHostRootFiber(
tag: RootTag,
isStrictMode: boolean,
concurrentUpdatesByDefaultOverride: null | boolean,
): Fiber {
let mode;
if (tag === ConcurrentRoot) {
mode = ConcurrentMode;
if (isStrictMode === true) {
mode |= StrictLegacyMode;
if (enableStrictEffects) {
mode |= StrictEffectsMode;
}
} else if (enableStrictEffects && createRootStrictEffectsByDefault) {
mode |= StrictLegacyMode | StrictEffectsMode;
}
if (
// We only use this flag for our repo tests to check both behaviors.
// TODO: Flip this flag and rename it something like "forceConcurrentByDefaultForTesting"
!enableSyncDefaultUpdates ||
// Only for internal experiments.
(allowConcurrentByDefault && concurrentUpdatesByDefaultOverride)
) {
mode |= ConcurrentUpdatesByDefaultMode;
}
} else {
mode = NoMode;
}
if (enableProfilerTimer && 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);
}
// 将 RootFiber 的格式 以实例的形式返回
const createFiber = function (
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
): Fiber {
// $FlowFixMe: the shapes are exact here but Flow doesn‘t like constructors
return new FiberNode(tag, pendingProps, key, mode);
};
// RootFiber 的格式,
// 此处的 pendingProps = null
// mode = 0b000000
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// Instance 实例
// 判断是否是初次,0=初次,1=不初次
this.tag = tag;
// 唯一标识
this.key = key;
// dom 的标签
this.elementType = null;
// JSX的类型,Component? Function? String
this.type = null;
// dom 元素
this.stateNode = null;
// Fiber
// 父级
this.return = null;
// 子级 Firber
this.child = null;
// 同级 Firber
this.sibling = null;
this.index = 0;
// ref 挂载
this.ref = null;
// 暂定
this.pendingProps = pendingProps;
this.memoizedProps = null;
// 队列
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
this.mode = mode;
// Effects
this.flags = NoFlags;
this.subtreeFlags = NoFlags;
this.deletions = null;
this.lanes = NoLanes;
this.childLanes = NoLanes;
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;
}
if (__DEV__) {
// This isn‘t directly used but is handy for debugging internals:
this._debugID = debugCounter++;
this._debugSource = null;
this._debugOwner = null;
this._debugNeedsRemount = false;
this._debugHookTypes = null;
if (!hasBadMapPolyfill && typeof Object.preventExtensions === ‘function‘) {
Object.preventExtensions(this);
}
}
}
7. 初始化队列,并将其挂载到 RootFiber 上
export function initializeUpdateQueue<State>(fiber: Fiber): void {
const queue: UpdateQueue<State> = {
baseState: fiber.memoizedState,
firstBaseUpdate: null,
lastBaseUpdate: null,
shared: {
pending: null,
interleaved: null,
lanes: NoLanes,
},
effects: null, // 更新事件
};
// 挂载队列
fiber.updateQueue = queue;
}
标签:ras empty oal with hand poi tables rop calling
原文地址:https://www.cnblogs.com/gqx-html/p/14832327.html