标签: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