一、作用
二、创建根
备注
createRootImpl()由 ReactDOMRoot#createRootImpl 实现assign()由 assign 实现
export function createRoot(
container: Element | Document | DocumentFragment,
options?: CreateRootOptions,
): RootType {
return createRootImpl(
container,
assign(
{
onUncaughtError: wwwOnUncaughtError,
onCaughtError: wwwOnCaughtError,
onDefaultTransitionIndicator: noopOnDefaultTransitionIndicator,
} as any,
options,
),
);
}
三、水合根
备注
hydrateRootImpl()由 ReactDOMRoot#hydrateRootImpl 实现assign()由 assign 实现
export function hydrateRoot(
container: Document | Element,
initialChildren: ReactNodeList,
options?: HydrateRootOptions,
): RootType {
return hydrateRootImpl(
container,
initialChildren,
assign(
{
onUncaughtError: wwwOnUncaughtError,
onCaughtError: wwwOnCaughtError,
onDefaultTransitionIndicator: noopOnDefaultTransitionIndicator,
} as any,
options,
),
);
}
四、查找 DOM 节点
备注
getComponentNameFromType()由 getComponentNameFromType 实现ELEMENT_NODE由 HTMLNodeType#ELEMENT_NODE 提供findHostInstanceWithWarning()由 ReactFiberReconciler#findHostInstanceWithWarning 实现findHostInstance()由 ReactFiberReconciler#findHostInstance 实现
export function findDOMNode(
// componentOrElement: Element | ?component(...props: any),
componentOrElement: Element | ?Component,
): null | Element | Text {
if (__DEV__) {
const owner = currentOwner;
if (owner !== null && isRendering && owner.stateNode !== null) {
const warnedAboutRefsInRender = owner.stateNode._warnedAboutRefsInRender;
if (!warnedAboutRefsInRender) {
console.error(
'%s is accessing findDOMNode inside its render(). ' +
'render() should be a pure function of props and state. It should ' +
'never access something that requires stale data from the previous ' +
'render, such as refs. Move this logic to componentDidMount and ' +
'componentDidUpdate instead.',
getComponentNameFromType(owner.type) || 'A component',
);
}
owner.stateNode._warnedAboutRefsInRender = true;
}
}
if (componentOrElement == null) {
return null;
}
if ((componentOrElement as any).nodeType === ELEMENT_NODE) {
return componentOrElement as any;
}
if (__DEV__) {
return findHostInstanceWithWarning(componentOrElement, 'findDOMNode');
}
return findHostInstance(componentOrElement);
}
五、渲染
备注
disableLegacyMode由 ReactFeatureFlags#disableLegacyMode 提供isValidContainer()由 ReactDOMContainer#isValidContainer 实现isContainerMarkedAsRoot()由 ReactDOMComponentTree#isContainerMarkedAsRoot 实现
export function render(
element: React$Element<any>,
container: Container,
callback: ?Function,
// ): component(...props: any) | PublicInstance | null {
): Component | PublicInstance | null {
if (disableLegacyMode) {
if (__DEV__) {
console.error(
'ReactDOM.render was removed in React 19. Use createRoot instead.',
);
}
throw new Error('ReactDOM: Unsupported Legacy Mode API.');
}
if (__DEV__) {
console.error(
'ReactDOM.render has not been supported since React 18. Use createRoot ' +
'instead. Until you switch to the new API, your app will behave as ' +
"if it's running React 17. Learn " +
'more: https://react.dev/link/switch-to-createroot',
);
}
if (!isValidContainer(container)) {
throw new Error('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 ReactDOMClient.createRoot(). This is not supported. ' +
'Did you mean to call root.render(element)?',
);
}
}
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
}
六、在节点卸载组件
备注
disableLegacyMode()由 ReactFeatureFlags#disableLegacyMode 实现isValidContainer()由 ReactDOMContainer#isValidContainer 实现isContainerMarkedAsRoot()由 ReactDOMComponentTree#isContainerMarkedAsRoot 实现getInstanceFromNode()由 ReactDOMComponentTree#getInstanceFromNode 实现updateContainerSync()由 ReactFiberReconciler#updateContainerSync 实现unmarkContainerAsRoot()由 ReactDOMComponentTree#unmarkContainerAsRoot 实现ELEMENT_NODE由 HTMLNodeType#ELEMENT_NODE 提供
export function unmountComponentAtNode(container: Container): boolean {
if (disableLegacyMode) {
if (__DEV__) {
console.error(
'unmountComponentAtNode was removed in React 19. Use root.unmount() instead.',
);
}
throw new Error('ReactDOM: Unsupported Legacy Mode API.');
}
if (!isValidContainer(container)) {
throw new Error('Target container is not a DOM element.');
}
if (__DEV__) {
const isModernRoot =
isContainerMarkedAsRoot(container) &&
container._reactRootContainer === undefined;
if (isModernRoot) {
console.error(
'You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' +
'passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?',
);
}
}
if (container._reactRootContainer) {
const root = container._reactRootContainer;
if (__DEV__) {
const rootEl = getReactRootElementInContainer(container);
const renderedByDifferentReact = rootEl && !getInstanceFromNode(rootEl);
if (renderedByDifferentReact) {
console.error(
"unmountComponentAtNode(): The node you're attempting to unmount " +
'was rendered by another copy of React.',
);
}
}
updateContainerSync(null, root, null, null);
flushSyncWork();
container._reactRootContainer = null;
unmarkContainerAsRoot(container);
return true;
} else {
if (__DEV__) {
const rootEl = getReactRootElementInContainer(container);
const hasNonRootReactChild = !!(rootEl && getInstanceFromNode(rootEl));
// Check if the container itself is a React root node.
// 检查容器本身是否是 React 根节点。
const isContainerReactRoot =
container.nodeType === ELEMENT_NODE &&
isValidContainer(container.parentNode) &&
!!container.parentNode._reactRootContainer;
if (hasNonRootReactChild) {
console.error(
"unmountComponentAtNode(): The node you're attempting to unmount " +
'was rendered by React and is not a top-level container. %s',
isContainerReactRoot
? 'You may have accidentally passed in a React root node instead ' +
'of its container.'
: 'Instead, have the parent component update its state and ' +
'rerender in order to remove this component.',
);
}
}
return false;
}
}
七、常量
1. ReactFiber错误对话框 WWW
备注
源码中 75 - 82 行
// Provided by www
// 由 www 提供
const ReactFiberErrorDialogWWW = require('ReactFiberErrorDialog');
if (typeof ReactFiberErrorDialogWWW.showErrorDialog !== 'function') {
throw new Error(
'Expected ReactFiberErrorDialog.showErrorDialog to be a function.',
);
}
2. 默认过渡指示器上不执行操作
备注
源码中 - 行
noop()由 noop 实现
const noopOnDefaultTransitionIndicator = noop;
3. 在可恢复错误上不操作
备注
源码中 214 - 216 行
noop()由 noop 实现
// This isn't reachable because onRecoverableError isn't called in the
// legacy API.
// 这是无法到达的,因为在旧版本 API 中不会调用 onRecoverableError。
const noopOnRecoverableError = noop;
八、变量
1. 顶层更新警告
源码中 167 - 200 行
备注
COMMENT_NODE由 HTMLNodeType#COMMENT_NODE 提供findHostInstanceWithNoPortals()由 ReactFiberReconciler#findHostInstanceWithNoPortals 实现getInstanceFromNode()由 ReactDOMComponentTree#getInstanceFromNode 实现
let topLevelUpdateWarnings;
if (__DEV__) {
topLevelUpdateWarnings = (container: Container) => {
if (container._reactRootContainer && container.nodeType !== COMMENT_NODE) {
const hostInstance = findHostInstanceWithNoPortals(
container._reactRootContainer.current,
);
if (hostInstance) {
if (hostInstance.parentNode !== container) {
console.error(
'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.',
);
}
}
}
const isRootRenderedBySomeReact = !!container._reactRootContainer;
const rootEl = getReactRootElementInContainer(container);
const hasNonRootReactChild = !!(rootEl && getInstanceFromNode(rootEl));
if (hasNonRootReactChild && !isRootRenderedBySomeReact) {
console.error(
'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.',
);
}
};
}
九、工具
1. www 未捕获错误
备注
defaultOnUncaughtError()由 ReactFiberReconciler#defaultOnUncaughtError 实现
function wwwOnUncaughtError(
error: mixed,
// errorInfo: {+componentStack?: ?string},
errorInfo: { componentStack?: ?string },
): void {
const componentStack =
errorInfo.componentStack != null ? errorInfo.componentStack : '';
const logError = ReactFiberErrorDialogWWW.showErrorDialog({
errorBoundary: null,
error,
componentStack,
});
// Allow injected showErrorDialog() to prevent default console.error logging.
// 允许注入的 showErrorDialog() 来阻止默认的 console.error 日志记录。
// This enables renderers like ReactNative to better manage redbox behavior.
// 这使得像 ReactNative 这样的渲染器能够更好地管理红框(redbox)行为。
if (logError === false) {
return;
}
defaultOnUncaughtError(error, errorInfo);
}
2. www 捕获错误
备注
defaultOnCaughtError()由 ReactFiberReconciler#defaultOnCaughtError 实现
function wwwOnCaughtError(
error: mixed,
errorInfo: {
// +componentStack?: ?string,
componentStack?: ?string;
// +errorBoundary?: ?component(),
errorBoundary?: ?Component;
},
): void {
const errorBoundary = errorInfo.errorBoundary;
const componentStack =
errorInfo.componentStack != null ? errorInfo.componentStack : '';
const logError = ReactFiberErrorDialogWWW.showErrorDialog({
errorBoundary,
error,
componentStack,
});
// Allow injected showErrorDialog() to prevent default console.error logging.
// 允许注入的 showErrorDialog() 来阻止默认的 console.error 日志。
// This enables renderers like ReactNative to better manage redbox behavior.
// 这使得像 ReactNative 这样的渲染器能够更好地管理红屏行为。
if (logError === false) {
return;
}
defaultOnCaughtError(error, errorInfo);
}
3. 在容器中获取 React 根元素
function getReactRootElementInContainer(container: any) {
if (!container) {
return null;
}
if (container.nodeType === DOCUMENT_NODE) {
return container.documentElement;
} else {
return container.firstChild;
}
}
4. 从 DOM 容器创建旧版根
备注
getPublicRootInstance()由 ReactFiberReconciler#getPublicRootInstance 实现createHydrationContainer()由 ReactFiberReconciler#createHydrationContainer 实现markContainerAsRoot()由 ReactDOMComponentTree#markContainerAsRoot 实现disableCommentsAsDOMContainers由 ReactFeatureFlags#disableCommentsAsDOMContainers 提供COMMENT_NODE由 HTMLNodeType#COMMENT_NODE 提供listenToAllSupportedEvents()由 DOMPluginEventSystem#listenToAllSupportedEvents 实现flushSyncWork()由 ReactFiberReconciler#flushSyncWork 实现clearContainer()由 ReactFiberConfigDOM#clearContainer 实现createContainer()由 ReactFiberReconciler#createContainer 实现updateContainerSync()由 ReactFiberReconciler#updateContainerSync 实现
function legacyCreateRootFromDOMContainer(
container: Container,
initialChildren: ReactNodeList,
// parentComponent: ?component(...props: any),
parentComponent: ?Component,
callback: ?Function,
isHydrationContainer: boolean,
): FiberRoot {
if (isHydrationContainer) {
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function () {
const instance = getPublicRootInstance(root);
originalCallback.call(instance);
};
}
const root: FiberRoot = createHydrationContainer(
initialChildren,
callback,
container,
LegacyRoot,
// 水合回调
null, // hydrationCallbacks
// 严格模式
false, // isStrictMode
// 默认覆盖的并发更新
false, // concurrentUpdatesByDefaultOverride,
// 标识符前缀
'', // identifierPrefix
wwwOnUncaughtError,
wwwOnCaughtError,
noopOnRecoverableError,
noopOnDefaultTransitionIndicator,
// TODO(luna) Support hydration later
// TODO(luna) 稍后支持水合
null,
null,
);
container._reactRootContainer = root;
markContainerAsRoot(root.current, container);
const rootContainerElement =
!disableCommentsAsDOMContainers && container.nodeType === COMMENT_NODE
? container.parentNode
: container;
listenToAllSupportedEvents(rootContainerElement);
flushSyncWork();
return root;
} else {
// First clear any existing content.
// 首先清除任何现有内容。
clearContainer(container);
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function () {
const instance = getPublicRootInstance(root);
originalCallback.call(instance);
};
}
const root = createContainer(
container,
LegacyRoot,
// 水合回调
null, // hydrationCallbacks
// 严格模式
false, // isStrictMode
// 默认并发更新覆盖
false, // concurrentUpdatesByDefaultOverride,
// 标识符前缀
'', // identifierPrefix
wwwOnUncaughtError,
wwwOnCaughtError,
noopOnRecoverableError,
noopOnDefaultTransitionIndicator,
// 过渡回调
null, // transitionCallbacks
);
container._reactRootContainer = root;
markContainerAsRoot(root.current, container);
const rootContainerElement =
!disableCommentsAsDOMContainers && container.nodeType === COMMENT_NODE
? container.parentNode
: container;
listenToAllSupportedEvents(rootContainerElement);
// Initial mount should not be batched.
// 初始挂载不应被批处理。
updateContainerSync(initialChildren, root, parentComponent, callback);
flushSyncWork();
return root;
}
}
5. 在无效回调时发出警告
function warnOnInvalidCallback(callback: mixed): void {
if (__DEV__) {
if (callback !== null && typeof callback !== 'function') {
console.error(
'Expected the last optional `callback` argument to be a ' +
'function. Instead received: %s.',
callback,
);
}
}
}
6. 传统渲染子树到容器
备注
getPublicRootInstance()由 ReactFiberReconciler#getPublicRootInstance 实现updateContainer()由 ReactFiberReconciler#updateContainer 实现
function legacyRenderSubtreeIntoContainer(
// parentComponent: ?component(...props: any),
parentComponent: ?Component,
children: ReactNodeList,
container: Container,
forceHydrate: boolean,
callback: ?Function,
// ): component(...props: any) | PublicInstance | null {
): Component | PublicInstance | null {
if (__DEV__) {
topLevelUpdateWarnings(container);
warnOnInvalidCallback(callback === undefined ? null : callback);
}
const maybeRoot = container._reactRootContainer;
let root: FiberRoot;
if (!maybeRoot) {
// Initial mount
// 初始挂载
root = legacyCreateRootFromDOMContainer(
container,
children,
parentComponent,
callback,
forceHydrate,
);
} else {
root = maybeRoot;
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function () {
const instance = getPublicRootInstance(root);
originalCallback.call(instance);
};
}
// Update
// 更新
updateContainer(children, root, parentComponent, callback);
}
return getPublicRootInstance(root);
}
十、转导
- 从 ReactFiberReconciler#batchedUpdates 转导了
batchedUpdates as unstable_batchedUpdates