Split ReactDOM entry point (#17331)
* Split ReactDOM entry point * BatchedRoot -> BlockingRoot
This commit is contained in:
parent
a7b4d51a20
commit
b8f8258775
|
@ -7,30 +7,28 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {RootType} from './ReactDOMRoot';
|
||||
import type {ReactNodeList} from 'shared/ReactTypes';
|
||||
import type {RootTag} from 'shared/ReactRootTags';
|
||||
// TODO: This type is shared between the reconciler and ReactDOM, but will
|
||||
// eventually be lifted out to the renderer.
|
||||
import type {FiberRoot} from 'react-reconciler/src/ReactFiberRoot';
|
||||
|
||||
import '../shared/checkReact';
|
||||
import './ReactDOMClientInjection';
|
||||
import {
|
||||
findDOMNode,
|
||||
render,
|
||||
hydrate,
|
||||
unstable_renderSubtreeIntoContainer,
|
||||
unmountComponentAtNode,
|
||||
} from './ReactDOMLegacy';
|
||||
import {createRoot, createBlockingRoot, isValidContainer} from './ReactDOMRoot';
|
||||
|
||||
import {
|
||||
findHostInstanceWithNoPortals,
|
||||
createContainer,
|
||||
updateContainer,
|
||||
batchedEventUpdates,
|
||||
batchedUpdates,
|
||||
unbatchedUpdates,
|
||||
discreteUpdates,
|
||||
flushDiscreteUpdates,
|
||||
flushSync,
|
||||
flushControlled,
|
||||
injectIntoDevTools,
|
||||
getPublicRootInstance,
|
||||
findHostInstance,
|
||||
findHostInstanceWithWarning,
|
||||
flushPassiveEffects,
|
||||
IsThisRendererActing,
|
||||
attemptSynchronousHydration,
|
||||
|
@ -53,11 +51,7 @@ import {
|
|||
accumulateTwoPhaseDispatches,
|
||||
accumulateDirectDispatches,
|
||||
} from 'legacy-events/EventPropagators';
|
||||
import {LegacyRoot, ConcurrentRoot, BatchedRoot} from 'shared/ReactRootTags';
|
||||
import {has as hasInstance} from 'shared/ReactInstanceMap';
|
||||
import ReactVersion from 'shared/ReactVersion';
|
||||
import ReactSharedInternals from 'shared/ReactSharedInternals';
|
||||
import getComponentName from 'shared/getComponentName';
|
||||
import invariant from 'shared/invariant';
|
||||
import lowPriorityWarningWithoutStack from 'shared/lowPriorityWarningWithoutStack';
|
||||
import warningWithoutStack from 'shared/warningWithoutStack';
|
||||
|
@ -68,9 +62,6 @@ import {
|
|||
getNodeFromInstance,
|
||||
getFiberCurrentPropsFromNode,
|
||||
getClosestInstanceFromNode,
|
||||
isContainerMarkedAsRoot,
|
||||
markContainerAsRoot,
|
||||
unmarkContainerAsRoot,
|
||||
} from './ReactDOMComponentTree';
|
||||
import {restoreControlledState} from './ReactDOMComponent';
|
||||
import {dispatchEvent} from '../events/ReactDOMEventListener';
|
||||
|
@ -79,26 +70,14 @@ import {
|
|||
setAttemptUserBlockingHydration,
|
||||
setAttemptContinuousHydration,
|
||||
setAttemptHydrationAtCurrentPriority,
|
||||
eagerlyTrapReplayableEvents,
|
||||
queueExplicitHydrationTarget,
|
||||
} from '../events/ReactDOMEventReplaying';
|
||||
import {
|
||||
ELEMENT_NODE,
|
||||
COMMENT_NODE,
|
||||
DOCUMENT_NODE,
|
||||
DOCUMENT_FRAGMENT_NODE,
|
||||
} from '../shared/HTMLNodeType';
|
||||
import {ROOT_ATTRIBUTE_NAME} from '../shared/DOMProperty';
|
||||
|
||||
setAttemptSynchronousHydration(attemptSynchronousHydration);
|
||||
setAttemptUserBlockingHydration(attemptUserBlockingHydration);
|
||||
setAttemptContinuousHydration(attemptContinuousHydration);
|
||||
setAttemptHydrationAtCurrentPriority(attemptHydrationAtCurrentPriority);
|
||||
|
||||
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
|
||||
|
||||
let topLevelUpdateWarnings;
|
||||
let warnOnInvalidCallback;
|
||||
let didWarnAboutUnstableCreatePortal = false;
|
||||
|
||||
if (__DEV__) {
|
||||
|
@ -119,176 +98,9 @@ if (__DEV__) {
|
|||
'polyfill in older browsers. https://fb.me/react-polyfills',
|
||||
);
|
||||
}
|
||||
|
||||
topLevelUpdateWarnings = (container: DOMContainer) => {
|
||||
if (container._reactRootContainer && container.nodeType !== COMMENT_NODE) {
|
||||
const hostInstance = findHostInstanceWithNoPortals(
|
||||
container._reactRootContainer._internalRoot.current,
|
||||
);
|
||||
if (hostInstance) {
|
||||
warningWithoutStack(
|
||||
hostInstance.parentNode === container,
|
||||
'render(...): 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));
|
||||
|
||||
warningWithoutStack(
|
||||
!hasNonRootReactChild || isRootRenderedBySomeReact,
|
||||
'render(...): 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.',
|
||||
);
|
||||
|
||||
warningWithoutStack(
|
||||
container.nodeType !== ELEMENT_NODE ||
|
||||
!((container: any): Element).tagName ||
|
||||
((container: any): Element).tagName.toUpperCase() !== 'BODY',
|
||||
'render(): Rendering components directly into document.body is ' +
|
||||
'discouraged, since its children are often manipulated by third-party ' +
|
||||
'scripts and browser extensions. This may lead to subtle ' +
|
||||
'reconciliation issues. Try rendering into a container element created ' +
|
||||
'for your app.',
|
||||
);
|
||||
};
|
||||
|
||||
warnOnInvalidCallback = function(callback: mixed, callerName: string) {
|
||||
warningWithoutStack(
|
||||
callback === null || typeof callback === 'function',
|
||||
'%s(...): Expected the last optional `callback` argument to be a ' +
|
||||
'function. Instead received: %s.',
|
||||
callerName,
|
||||
callback,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
setRestoreImplementation(restoreControlledState);
|
||||
|
||||
export type DOMContainer =
|
||||
| (Element & {
|
||||
_reactRootContainer: ?_ReactRoot,
|
||||
})
|
||||
| (Document & {
|
||||
_reactRootContainer: ?_ReactRoot,
|
||||
});
|
||||
|
||||
type _ReactRoot = {
|
||||
render(children: ReactNodeList, callback: ?() => mixed): void,
|
||||
unmount(callback: ?() => mixed): void,
|
||||
|
||||
_internalRoot: FiberRoot,
|
||||
};
|
||||
|
||||
function createRootImpl(
|
||||
container: DOMContainer,
|
||||
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 root = createContainer(container, tag, hydrate, hydrationCallbacks);
|
||||
markContainerAsRoot(root.current, container);
|
||||
if (hydrate && tag !== LegacyRoot) {
|
||||
const doc =
|
||||
container.nodeType === DOCUMENT_NODE
|
||||
? container
|
||||
: container.ownerDocument;
|
||||
eagerlyTrapReplayableEvents(doc);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
function ReactBlockingRoot(
|
||||
container: DOMContainer,
|
||||
tag: RootTag,
|
||||
options: void | RootOptions,
|
||||
) {
|
||||
this._internalRoot = createRootImpl(container, tag, options);
|
||||
}
|
||||
|
||||
function ReactRoot(container: DOMContainer, options: void | RootOptions) {
|
||||
this._internalRoot = createRootImpl(container, ConcurrentRoot, options);
|
||||
}
|
||||
|
||||
ReactRoot.prototype.render = ReactBlockingRoot.prototype.render = function(
|
||||
children: ReactNodeList,
|
||||
callback: ?() => mixed,
|
||||
): void {
|
||||
const root = this._internalRoot;
|
||||
const cb = callback === undefined ? null : callback;
|
||||
if (__DEV__) {
|
||||
warnOnInvalidCallback(cb, 'render');
|
||||
}
|
||||
updateContainer(children, root, null, cb);
|
||||
};
|
||||
|
||||
ReactRoot.prototype.unmount = ReactBlockingRoot.prototype.unmount = function(
|
||||
callback: ?() => mixed,
|
||||
): void {
|
||||
const root = this._internalRoot;
|
||||
const cb = callback === undefined ? null : callback;
|
||||
if (__DEV__) {
|
||||
warnOnInvalidCallback(cb, 'render');
|
||||
}
|
||||
const container = root.containerInfo;
|
||||
updateContainer(null, root, null, () => {
|
||||
unmarkContainerAsRoot(container);
|
||||
if (cb !== null) {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* True if the supplied DOM node is a valid node element.
|
||||
*
|
||||
* @param {?DOMElement} node The candidate DOM node.
|
||||
* @return {boolean} True if the DOM is a valid DOM node.
|
||||
* @internal
|
||||
*/
|
||||
function isValidContainer(node) {
|
||||
return !!(
|
||||
node &&
|
||||
(node.nodeType === ELEMENT_NODE ||
|
||||
node.nodeType === DOCUMENT_NODE ||
|
||||
node.nodeType === DOCUMENT_FRAGMENT_NODE ||
|
||||
(node.nodeType === COMMENT_NODE &&
|
||||
node.nodeValue === ' react-mount-point-unstable '))
|
||||
);
|
||||
}
|
||||
|
||||
function getReactRootElementInContainer(container: any) {
|
||||
if (!container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (container.nodeType === DOCUMENT_NODE) {
|
||||
return container.documentElement;
|
||||
} else {
|
||||
return container.firstChild;
|
||||
}
|
||||
}
|
||||
|
||||
function shouldHydrateDueToLegacyHeuristic(container) {
|
||||
const rootElement = getReactRootElementInContainer(container);
|
||||
return !!(
|
||||
rootElement &&
|
||||
rootElement.nodeType === ELEMENT_NODE &&
|
||||
rootElement.hasAttribute(ROOT_ATTRIBUTE_NAME)
|
||||
);
|
||||
}
|
||||
|
||||
setBatchingImplementation(
|
||||
batchedUpdates,
|
||||
discreteUpdates,
|
||||
|
@ -296,109 +108,13 @@ setBatchingImplementation(
|
|||
batchedEventUpdates,
|
||||
);
|
||||
|
||||
let warnedAboutHydrateAPI = false;
|
||||
|
||||
function legacyCreateRootFromDOMContainer(
|
||||
container: DOMContainer,
|
||||
forceHydrate: boolean,
|
||||
): _ReactRoot {
|
||||
const shouldHydrate =
|
||||
forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
|
||||
// First clear any existing content.
|
||||
if (!shouldHydrate) {
|
||||
let warned = false;
|
||||
let rootSibling;
|
||||
while ((rootSibling = container.lastChild)) {
|
||||
if (__DEV__) {
|
||||
if (
|
||||
!warned &&
|
||||
rootSibling.nodeType === ELEMENT_NODE &&
|
||||
(rootSibling: any).hasAttribute(ROOT_ATTRIBUTE_NAME)
|
||||
) {
|
||||
warned = true;
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'render(): Target node has markup rendered by React, but there ' +
|
||||
'are unrelated nodes as well. This is most commonly caused by ' +
|
||||
'white-space inserted around server-rendered markup.',
|
||||
);
|
||||
}
|
||||
}
|
||||
container.removeChild(rootSibling);
|
||||
}
|
||||
}
|
||||
if (__DEV__) {
|
||||
if (shouldHydrate && !forceHydrate && !warnedAboutHydrateAPI) {
|
||||
warnedAboutHydrateAPI = true;
|
||||
lowPriorityWarningWithoutStack(
|
||||
false,
|
||||
'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
|
||||
'will stop working in React v17. Replace the ReactDOM.render() call ' +
|
||||
'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy roots are not batched.
|
||||
return new ReactBlockingRoot(
|
||||
container,
|
||||
LegacyRoot,
|
||||
shouldHydrate
|
||||
? {
|
||||
hydrate: true,
|
||||
}
|
||||
: undefined,
|
||||
);
|
||||
}
|
||||
|
||||
function legacyRenderSubtreeIntoContainer(
|
||||
parentComponent: ?React$Component<any, any>,
|
||||
children: ReactNodeList,
|
||||
container: DOMContainer,
|
||||
forceHydrate: boolean,
|
||||
callback: ?Function,
|
||||
) {
|
||||
if (__DEV__) {
|
||||
topLevelUpdateWarnings(container);
|
||||
warnOnInvalidCallback(callback === undefined ? null : callback, 'render');
|
||||
}
|
||||
|
||||
// TODO: Without `any` type, Flow says "Property cannot be accessed on any
|
||||
// member of intersection type." Whyyyyyy.
|
||||
let root: _ReactRoot = (container._reactRootContainer: any);
|
||||
let fiberRoot;
|
||||
if (!root) {
|
||||
// Initial mount
|
||||
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
|
||||
container,
|
||||
forceHydrate,
|
||||
);
|
||||
fiberRoot = root._internalRoot;
|
||||
if (typeof callback === 'function') {
|
||||
const originalCallback = callback;
|
||||
callback = function() {
|
||||
const instance = getPublicRootInstance(fiberRoot);
|
||||
originalCallback.call(instance);
|
||||
};
|
||||
}
|
||||
// Initial mount should not be batched.
|
||||
unbatchedUpdates(() => {
|
||||
updateContainer(children, fiberRoot, parentComponent, callback);
|
||||
export type DOMContainer =
|
||||
| (Element & {
|
||||
_reactRootContainer: ?RootType,
|
||||
})
|
||||
| (Document & {
|
||||
_reactRootContainer: ?RootType,
|
||||
});
|
||||
} else {
|
||||
fiberRoot = root._internalRoot;
|
||||
if (typeof callback === 'function') {
|
||||
const originalCallback = callback;
|
||||
callback = function() {
|
||||
const instance = getPublicRootInstance(fiberRoot);
|
||||
originalCallback.call(instance);
|
||||
};
|
||||
}
|
||||
// Update
|
||||
updateContainer(children, fiberRoot, parentComponent, callback);
|
||||
}
|
||||
return getPublicRootInstance(fiberRoot);
|
||||
}
|
||||
|
||||
function createPortal(
|
||||
children: ReactNodeList,
|
||||
|
@ -416,186 +132,12 @@ function createPortal(
|
|||
const ReactDOM: Object = {
|
||||
createPortal,
|
||||
|
||||
findDOMNode(
|
||||
componentOrElement: Element | ?React$Component<any, any>,
|
||||
): null | Element | Text {
|
||||
if (__DEV__) {
|
||||
let owner = (ReactCurrentOwner.current: any);
|
||||
if (owner !== null && owner.stateNode !== null) {
|
||||
const warnedAboutRefsInRender =
|
||||
owner.stateNode._warnedAboutRefsInRender;
|
||||
warningWithoutStack(
|
||||
warnedAboutRefsInRender,
|
||||
'%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.',
|
||||
getComponentName(owner.type) || 'A component',
|
||||
);
|
||||
owner.stateNode._warnedAboutRefsInRender = true;
|
||||
}
|
||||
}
|
||||
if (componentOrElement == null) {
|
||||
return null;
|
||||
}
|
||||
if ((componentOrElement: any).nodeType === ELEMENT_NODE) {
|
||||
return (componentOrElement: any);
|
||||
}
|
||||
if (__DEV__) {
|
||||
return findHostInstanceWithWarning(componentOrElement, 'findDOMNode');
|
||||
}
|
||||
return findHostInstance(componentOrElement);
|
||||
},
|
||||
|
||||
hydrate(element: React$Node, container: DOMContainer, callback: ?Function) {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'Target container is not a DOM element.',
|
||||
);
|
||||
if (__DEV__) {
|
||||
const isModernRoot =
|
||||
isContainerMarkedAsRoot(container) &&
|
||||
container._reactRootContainer === undefined;
|
||||
if (isModernRoot) {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'You are calling ReactDOM.hydrate() on a container that was previously ' +
|
||||
'passed to ReactDOM.createRoot(). This is not supported. ' +
|
||||
'Did you mean to call createRoot(container, {hydrate: true}).render(element)?',
|
||||
);
|
||||
}
|
||||
}
|
||||
// TODO: throw or warn if we couldn't hydrate?
|
||||
return legacyRenderSubtreeIntoContainer(
|
||||
null,
|
||||
element,
|
||||
container,
|
||||
true,
|
||||
callback,
|
||||
);
|
||||
},
|
||||
|
||||
render(
|
||||
element: React$Element<any>,
|
||||
container: DOMContainer,
|
||||
callback: ?Function,
|
||||
) {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'Target container is not a DOM element.',
|
||||
);
|
||||
if (__DEV__) {
|
||||
const isModernRoot =
|
||||
isContainerMarkedAsRoot(container) &&
|
||||
container._reactRootContainer === undefined;
|
||||
if (isModernRoot) {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'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,
|
||||
);
|
||||
},
|
||||
|
||||
unstable_renderSubtreeIntoContainer(
|
||||
parentComponent: React$Component<any, any>,
|
||||
element: React$Element<any>,
|
||||
containerNode: DOMContainer,
|
||||
callback: ?Function,
|
||||
) {
|
||||
invariant(
|
||||
isValidContainer(containerNode),
|
||||
'Target container is not a DOM element.',
|
||||
);
|
||||
invariant(
|
||||
parentComponent != null && hasInstance(parentComponent),
|
||||
'parentComponent must be a valid React Component',
|
||||
);
|
||||
return legacyRenderSubtreeIntoContainer(
|
||||
parentComponent,
|
||||
element,
|
||||
containerNode,
|
||||
false,
|
||||
callback,
|
||||
);
|
||||
},
|
||||
|
||||
unmountComponentAtNode(container: DOMContainer) {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'unmountComponentAtNode(...): Target container is not a DOM element.',
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
const isModernRoot =
|
||||
isContainerMarkedAsRoot(container) &&
|
||||
container._reactRootContainer === undefined;
|
||||
if (isModernRoot) {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' +
|
||||
'passed to ReactDOM.createRoot(). This is not supported. Did you mean to call root.unmount()?',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (container._reactRootContainer) {
|
||||
if (__DEV__) {
|
||||
const rootEl = getReactRootElementInContainer(container);
|
||||
const renderedByDifferentReact = rootEl && !getInstanceFromNode(rootEl);
|
||||
warningWithoutStack(
|
||||
!renderedByDifferentReact,
|
||||
"unmountComponentAtNode(): The node you're attempting to unmount " +
|
||||
'was rendered by another copy of React.',
|
||||
);
|
||||
}
|
||||
|
||||
// Unmount should not be batched.
|
||||
unbatchedUpdates(() => {
|
||||
legacyRenderSubtreeIntoContainer(null, null, container, false, () => {
|
||||
container._reactRootContainer = null;
|
||||
unmarkContainerAsRoot(container);
|
||||
});
|
||||
});
|
||||
// If you call unmountComponentAtNode twice in quick succession, you'll
|
||||
// get `true` twice. That's probably fine?
|
||||
return true;
|
||||
} else {
|
||||
if (__DEV__) {
|
||||
const rootEl = getReactRootElementInContainer(container);
|
||||
const hasNonRootReactChild = !!(rootEl && getInstanceFromNode(rootEl));
|
||||
|
||||
// Check if the container itself is a React root node.
|
||||
const isContainerReactRoot =
|
||||
container.nodeType === ELEMENT_NODE &&
|
||||
isValidContainer(container.parentNode) &&
|
||||
!!container.parentNode._reactRootContainer;
|
||||
|
||||
warningWithoutStack(
|
||||
!hasNonRootReactChild,
|
||||
"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;
|
||||
}
|
||||
},
|
||||
// Legacy
|
||||
findDOMNode,
|
||||
hydrate,
|
||||
render,
|
||||
unstable_renderSubtreeIntoContainer,
|
||||
unmountComponentAtNode,
|
||||
|
||||
// Temporary alias since we already shipped React 16 RC with it.
|
||||
// TODO: remove in React 17.
|
||||
|
@ -638,59 +180,6 @@ const ReactDOM: Object = {
|
|||
},
|
||||
};
|
||||
|
||||
type RootOptions = {
|
||||
hydrate?: boolean,
|
||||
hydrationOptions?: {
|
||||
onHydrated?: (suspenseNode: Comment) => void,
|
||||
onDeleted?: (suspenseNode: Comment) => void,
|
||||
},
|
||||
};
|
||||
|
||||
function createRoot(
|
||||
container: DOMContainer,
|
||||
options?: RootOptions,
|
||||
): _ReactRoot {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'createRoot(...): Target container is not a DOM element.',
|
||||
);
|
||||
warnIfReactDOMContainerInDEV(container);
|
||||
return new ReactRoot(container, options);
|
||||
}
|
||||
|
||||
function createBlockingRoot(
|
||||
container: DOMContainer,
|
||||
options?: RootOptions,
|
||||
): _ReactRoot {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'createRoot(...): Target container is not a DOM element.',
|
||||
);
|
||||
warnIfReactDOMContainerInDEV(container);
|
||||
return new ReactBlockingRoot(container, BatchedRoot, options);
|
||||
}
|
||||
|
||||
function warnIfReactDOMContainerInDEV(container) {
|
||||
if (__DEV__) {
|
||||
if (isContainerMarkedAsRoot(container)) {
|
||||
if (container._reactRootContainer) {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'You are calling ReactDOM.createRoot() on a container that was previously ' +
|
||||
'passed to ReactDOM.render(). This is not supported.',
|
||||
);
|
||||
} else {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'You are calling ReactDOM.createRoot() on a container that ' +
|
||||
'has already been passed to createRoot() before. Instead, call ' +
|
||||
'root.render() on the existing root instead if you want to update it.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exposeConcurrentModeAPIs) {
|
||||
ReactDOM.createRoot = createRoot;
|
||||
ReactDOM.createBlockingRoot = createBlockingRoot;
|
||||
|
|
|
@ -0,0 +1,396 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {DOMContainer} from './ReactDOM';
|
||||
import type {RootType} from './ReactDOMRoot';
|
||||
import type {ReactNodeList} from 'shared/ReactTypes';
|
||||
|
||||
import {
|
||||
getInstanceFromNode,
|
||||
isContainerMarkedAsRoot,
|
||||
unmarkContainerAsRoot,
|
||||
} from './ReactDOMComponentTree';
|
||||
import {
|
||||
createLegacyRoot,
|
||||
isValidContainer,
|
||||
warnOnInvalidCallback,
|
||||
} from './ReactDOMRoot';
|
||||
import {ROOT_ATTRIBUTE_NAME} from '../shared/DOMProperty';
|
||||
import {
|
||||
DOCUMENT_NODE,
|
||||
ELEMENT_NODE,
|
||||
COMMENT_NODE,
|
||||
} from '../shared/HTMLNodeType';
|
||||
|
||||
import {
|
||||
findHostInstanceWithNoPortals,
|
||||
updateContainer,
|
||||
unbatchedUpdates,
|
||||
getPublicRootInstance,
|
||||
findHostInstance,
|
||||
findHostInstanceWithWarning,
|
||||
} from 'react-reconciler/inline.dom';
|
||||
import getComponentName from 'shared/getComponentName';
|
||||
import invariant from 'shared/invariant';
|
||||
import lowPriorityWarningWithoutStack from 'shared/lowPriorityWarningWithoutStack';
|
||||
import warningWithoutStack from 'shared/warningWithoutStack';
|
||||
import ReactSharedInternals from 'shared/ReactSharedInternals';
|
||||
import {has as hasInstance} from 'shared/ReactInstanceMap';
|
||||
|
||||
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
|
||||
|
||||
let topLevelUpdateWarnings;
|
||||
let warnedAboutHydrateAPI = false;
|
||||
|
||||
if (__DEV__) {
|
||||
topLevelUpdateWarnings = (container: DOMContainer) => {
|
||||
if (container._reactRootContainer && container.nodeType !== COMMENT_NODE) {
|
||||
const hostInstance = findHostInstanceWithNoPortals(
|
||||
container._reactRootContainer._internalRoot.current,
|
||||
);
|
||||
if (hostInstance) {
|
||||
warningWithoutStack(
|
||||
hostInstance.parentNode === container,
|
||||
'render(...): 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));
|
||||
|
||||
warningWithoutStack(
|
||||
!hasNonRootReactChild || isRootRenderedBySomeReact,
|
||||
'render(...): 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.',
|
||||
);
|
||||
|
||||
warningWithoutStack(
|
||||
container.nodeType !== ELEMENT_NODE ||
|
||||
!((container: any): Element).tagName ||
|
||||
((container: any): Element).tagName.toUpperCase() !== 'BODY',
|
||||
'render(): Rendering components directly into document.body is ' +
|
||||
'discouraged, since its children are often manipulated by third-party ' +
|
||||
'scripts and browser extensions. This may lead to subtle ' +
|
||||
'reconciliation issues. Try rendering into a container element created ' +
|
||||
'for your app.',
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
function getReactRootElementInContainer(container: any) {
|
||||
if (!container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (container.nodeType === DOCUMENT_NODE) {
|
||||
return container.documentElement;
|
||||
} else {
|
||||
return container.firstChild;
|
||||
}
|
||||
}
|
||||
|
||||
function shouldHydrateDueToLegacyHeuristic(container) {
|
||||
const rootElement = getReactRootElementInContainer(container);
|
||||
return !!(
|
||||
rootElement &&
|
||||
rootElement.nodeType === ELEMENT_NODE &&
|
||||
rootElement.hasAttribute(ROOT_ATTRIBUTE_NAME)
|
||||
);
|
||||
}
|
||||
|
||||
function legacyCreateRootFromDOMContainer(
|
||||
container: DOMContainer,
|
||||
forceHydrate: boolean,
|
||||
): RootType {
|
||||
const shouldHydrate =
|
||||
forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
|
||||
// First clear any existing content.
|
||||
if (!shouldHydrate) {
|
||||
let warned = false;
|
||||
let rootSibling;
|
||||
while ((rootSibling = container.lastChild)) {
|
||||
if (__DEV__) {
|
||||
if (
|
||||
!warned &&
|
||||
rootSibling.nodeType === ELEMENT_NODE &&
|
||||
(rootSibling: any).hasAttribute(ROOT_ATTRIBUTE_NAME)
|
||||
) {
|
||||
warned = true;
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'render(): Target node has markup rendered by React, but there ' +
|
||||
'are unrelated nodes as well. This is most commonly caused by ' +
|
||||
'white-space inserted around server-rendered markup.',
|
||||
);
|
||||
}
|
||||
}
|
||||
container.removeChild(rootSibling);
|
||||
}
|
||||
}
|
||||
if (__DEV__) {
|
||||
if (shouldHydrate && !forceHydrate && !warnedAboutHydrateAPI) {
|
||||
warnedAboutHydrateAPI = true;
|
||||
lowPriorityWarningWithoutStack(
|
||||
false,
|
||||
'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
|
||||
'will stop working in React v17. Replace the ReactDOM.render() call ' +
|
||||
'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return createLegacyRoot(
|
||||
container,
|
||||
shouldHydrate
|
||||
? {
|
||||
hydrate: true,
|
||||
}
|
||||
: undefined,
|
||||
);
|
||||
}
|
||||
|
||||
function legacyRenderSubtreeIntoContainer(
|
||||
parentComponent: ?React$Component<any, any>,
|
||||
children: ReactNodeList,
|
||||
container: DOMContainer,
|
||||
forceHydrate: boolean,
|
||||
callback: ?Function,
|
||||
) {
|
||||
if (__DEV__) {
|
||||
topLevelUpdateWarnings(container);
|
||||
warnOnInvalidCallback(callback === undefined ? null : callback, 'render');
|
||||
}
|
||||
|
||||
// TODO: Without `any` type, Flow says "Property cannot be accessed on any
|
||||
// member of intersection type." Whyyyyyy.
|
||||
let root: RootType = (container._reactRootContainer: any);
|
||||
let fiberRoot;
|
||||
if (!root) {
|
||||
// Initial mount
|
||||
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
|
||||
container,
|
||||
forceHydrate,
|
||||
);
|
||||
fiberRoot = root._internalRoot;
|
||||
if (typeof callback === 'function') {
|
||||
const originalCallback = callback;
|
||||
callback = function() {
|
||||
const instance = getPublicRootInstance(fiberRoot);
|
||||
originalCallback.call(instance);
|
||||
};
|
||||
}
|
||||
// Initial mount should not be batched.
|
||||
unbatchedUpdates(() => {
|
||||
updateContainer(children, fiberRoot, parentComponent, callback);
|
||||
});
|
||||
} else {
|
||||
fiberRoot = root._internalRoot;
|
||||
if (typeof callback === 'function') {
|
||||
const originalCallback = callback;
|
||||
callback = function() {
|
||||
const instance = getPublicRootInstance(fiberRoot);
|
||||
originalCallback.call(instance);
|
||||
};
|
||||
}
|
||||
// Update
|
||||
updateContainer(children, fiberRoot, parentComponent, callback);
|
||||
}
|
||||
return getPublicRootInstance(fiberRoot);
|
||||
}
|
||||
|
||||
export function findDOMNode(
|
||||
componentOrElement: Element | ?React$Component<any, any>,
|
||||
): null | Element | Text {
|
||||
if (__DEV__) {
|
||||
let owner = (ReactCurrentOwner.current: any);
|
||||
if (owner !== null && owner.stateNode !== null) {
|
||||
const warnedAboutRefsInRender = owner.stateNode._warnedAboutRefsInRender;
|
||||
warningWithoutStack(
|
||||
warnedAboutRefsInRender,
|
||||
'%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.',
|
||||
getComponentName(owner.type) || 'A component',
|
||||
);
|
||||
owner.stateNode._warnedAboutRefsInRender = true;
|
||||
}
|
||||
}
|
||||
if (componentOrElement == null) {
|
||||
return null;
|
||||
}
|
||||
if ((componentOrElement: any).nodeType === ELEMENT_NODE) {
|
||||
return (componentOrElement: any);
|
||||
}
|
||||
if (__DEV__) {
|
||||
return findHostInstanceWithWarning(componentOrElement, 'findDOMNode');
|
||||
}
|
||||
return findHostInstance(componentOrElement);
|
||||
}
|
||||
|
||||
export function hydrate(
|
||||
element: React$Node,
|
||||
container: DOMContainer,
|
||||
callback: ?Function,
|
||||
) {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'Target container is not a DOM element.',
|
||||
);
|
||||
if (__DEV__) {
|
||||
const isModernRoot =
|
||||
isContainerMarkedAsRoot(container) &&
|
||||
container._reactRootContainer === undefined;
|
||||
if (isModernRoot) {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'You are calling ReactDOM.hydrate() on a container that was previously ' +
|
||||
'passed to ReactDOM.createRoot(). This is not supported. ' +
|
||||
'Did you mean to call createRoot(container, {hydrate: true}).render(element)?',
|
||||
);
|
||||
}
|
||||
}
|
||||
// TODO: throw or warn if we couldn't hydrate?
|
||||
return legacyRenderSubtreeIntoContainer(
|
||||
null,
|
||||
element,
|
||||
container,
|
||||
true,
|
||||
callback,
|
||||
);
|
||||
}
|
||||
|
||||
export function render(
|
||||
element: React$Element<any>,
|
||||
container: DOMContainer,
|
||||
callback: ?Function,
|
||||
) {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'Target container is not a DOM element.',
|
||||
);
|
||||
if (__DEV__) {
|
||||
const isModernRoot =
|
||||
isContainerMarkedAsRoot(container) &&
|
||||
container._reactRootContainer === undefined;
|
||||
if (isModernRoot) {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'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,
|
||||
);
|
||||
}
|
||||
|
||||
export function unstable_renderSubtreeIntoContainer(
|
||||
parentComponent: React$Component<any, any>,
|
||||
element: React$Element<any>,
|
||||
containerNode: DOMContainer,
|
||||
callback: ?Function,
|
||||
) {
|
||||
invariant(
|
||||
isValidContainer(containerNode),
|
||||
'Target container is not a DOM element.',
|
||||
);
|
||||
invariant(
|
||||
parentComponent != null && hasInstance(parentComponent),
|
||||
'parentComponent must be a valid React Component',
|
||||
);
|
||||
return legacyRenderSubtreeIntoContainer(
|
||||
parentComponent,
|
||||
element,
|
||||
containerNode,
|
||||
false,
|
||||
callback,
|
||||
);
|
||||
}
|
||||
|
||||
export function unmountComponentAtNode(container: DOMContainer) {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'unmountComponentAtNode(...): Target container is not a DOM element.',
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
const isModernRoot =
|
||||
isContainerMarkedAsRoot(container) &&
|
||||
container._reactRootContainer === undefined;
|
||||
if (isModernRoot) {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' +
|
||||
'passed to ReactDOM.createRoot(). This is not supported. Did you mean to call root.unmount()?',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (container._reactRootContainer) {
|
||||
if (__DEV__) {
|
||||
const rootEl = getReactRootElementInContainer(container);
|
||||
const renderedByDifferentReact = rootEl && !getInstanceFromNode(rootEl);
|
||||
warningWithoutStack(
|
||||
!renderedByDifferentReact,
|
||||
"unmountComponentAtNode(): The node you're attempting to unmount " +
|
||||
'was rendered by another copy of React.',
|
||||
);
|
||||
}
|
||||
|
||||
// Unmount should not be batched.
|
||||
unbatchedUpdates(() => {
|
||||
legacyRenderSubtreeIntoContainer(null, null, container, false, () => {
|
||||
container._reactRootContainer = null;
|
||||
unmarkContainerAsRoot(container);
|
||||
});
|
||||
});
|
||||
// If you call unmountComponentAtNode twice in quick succession, you'll
|
||||
// get `true` twice. That's probably fine?
|
||||
return true;
|
||||
} else {
|
||||
if (__DEV__) {
|
||||
const rootEl = getReactRootElementInContainer(container);
|
||||
const hasNonRootReactChild = !!(rootEl && getInstanceFromNode(rootEl));
|
||||
|
||||
// Check if the container itself is a React root node.
|
||||
const isContainerReactRoot =
|
||||
container.nodeType === ELEMENT_NODE &&
|
||||
isValidContainer(container.parentNode) &&
|
||||
!!container.parentNode._reactRootContainer;
|
||||
|
||||
warningWithoutStack(
|
||||
!hasNonRootReactChild,
|
||||
"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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {DOMContainer} from './ReactDOM';
|
||||
import type {RootTag} from 'shared/ReactRootTags';
|
||||
import type {ReactNodeList} from 'shared/ReactTypes';
|
||||
// TODO: This type is shared between the reconciler and ReactDOM, but will
|
||||
// eventually be lifted out to the renderer.
|
||||
import type {FiberRoot} from 'react-reconciler/src/ReactFiberRoot';
|
||||
|
||||
export type RootType = {
|
||||
render(children: ReactNodeList, callback: ?() => mixed): void,
|
||||
unmount(callback: ?() => mixed): void,
|
||||
|
||||
_internalRoot: FiberRoot,
|
||||
};
|
||||
|
||||
export type RootOptions = {
|
||||
hydrate?: boolean,
|
||||
hydrationOptions?: {
|
||||
onHydrated?: (suspenseNode: Comment) => void,
|
||||
onDeleted?: (suspenseNode: Comment) => void,
|
||||
},
|
||||
};
|
||||
|
||||
import {
|
||||
isContainerMarkedAsRoot,
|
||||
markContainerAsRoot,
|
||||
unmarkContainerAsRoot,
|
||||
} from './ReactDOMComponentTree';
|
||||
import {eagerlyTrapReplayableEvents} from '../events/ReactDOMEventReplaying';
|
||||
import {
|
||||
ELEMENT_NODE,
|
||||
COMMENT_NODE,
|
||||
DOCUMENT_NODE,
|
||||
DOCUMENT_FRAGMENT_NODE,
|
||||
} from '../shared/HTMLNodeType';
|
||||
|
||||
import {createContainer, updateContainer} from 'react-reconciler/inline.dom';
|
||||
import invariant from 'shared/invariant';
|
||||
import warningWithoutStack from 'shared/warningWithoutStack';
|
||||
import {BlockingRoot, ConcurrentRoot, LegacyRoot} from 'shared/ReactRootTags';
|
||||
|
||||
function ReactDOMRoot(container: DOMContainer, options: void | RootOptions) {
|
||||
this._internalRoot = createRootImpl(container, ConcurrentRoot, options);
|
||||
}
|
||||
|
||||
function ReactDOMBlockingRoot(
|
||||
container: DOMContainer,
|
||||
tag: RootTag,
|
||||
options: void | RootOptions,
|
||||
) {
|
||||
this._internalRoot = createRootImpl(container, tag, options);
|
||||
}
|
||||
|
||||
ReactDOMRoot.prototype.render = ReactDOMBlockingRoot.prototype.render = function(
|
||||
children: ReactNodeList,
|
||||
callback: ?() => mixed,
|
||||
): void {
|
||||
const root = this._internalRoot;
|
||||
const cb = callback === undefined ? null : callback;
|
||||
if (__DEV__) {
|
||||
warnOnInvalidCallback(cb, 'render');
|
||||
}
|
||||
updateContainer(children, root, null, cb);
|
||||
};
|
||||
|
||||
ReactDOMRoot.prototype.unmount = ReactDOMBlockingRoot.prototype.unmount = function(
|
||||
callback: ?() => mixed,
|
||||
): void {
|
||||
const root = this._internalRoot;
|
||||
const cb = callback === undefined ? null : callback;
|
||||
if (__DEV__) {
|
||||
warnOnInvalidCallback(cb, 'render');
|
||||
}
|
||||
const container = root.containerInfo;
|
||||
updateContainer(null, root, null, () => {
|
||||
unmarkContainerAsRoot(container);
|
||||
if (cb !== null) {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function createRootImpl(
|
||||
container: DOMContainer,
|
||||
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 root = createContainer(container, tag, hydrate, hydrationCallbacks);
|
||||
markContainerAsRoot(root.current, container);
|
||||
if (hydrate && tag !== LegacyRoot) {
|
||||
const doc =
|
||||
container.nodeType === DOCUMENT_NODE
|
||||
? container
|
||||
: container.ownerDocument;
|
||||
eagerlyTrapReplayableEvents(doc);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
export function createRoot(
|
||||
container: DOMContainer,
|
||||
options?: RootOptions,
|
||||
): RootType {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'createRoot(...): Target container is not a DOM element.',
|
||||
);
|
||||
warnIfReactDOMContainerInDEV(container);
|
||||
return new ReactDOMRoot(container, options);
|
||||
}
|
||||
|
||||
export function createBlockingRoot(
|
||||
container: DOMContainer,
|
||||
options?: RootOptions,
|
||||
): RootType {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'createRoot(...): Target container is not a DOM element.',
|
||||
);
|
||||
warnIfReactDOMContainerInDEV(container);
|
||||
return new ReactDOMBlockingRoot(container, BlockingRoot, options);
|
||||
}
|
||||
|
||||
export function createLegacyRoot(
|
||||
container: DOMContainer,
|
||||
options?: RootOptions,
|
||||
): RootType {
|
||||
return new ReactDOMBlockingRoot(container, LegacyRoot, options);
|
||||
}
|
||||
|
||||
export function isValidContainer(node: mixed): boolean {
|
||||
return !!(
|
||||
node &&
|
||||
(node.nodeType === ELEMENT_NODE ||
|
||||
node.nodeType === DOCUMENT_NODE ||
|
||||
node.nodeType === DOCUMENT_FRAGMENT_NODE ||
|
||||
(node.nodeType === COMMENT_NODE &&
|
||||
(node: any).nodeValue === ' react-mount-point-unstable '))
|
||||
);
|
||||
}
|
||||
|
||||
export function warnOnInvalidCallback(
|
||||
callback: mixed,
|
||||
callerName: string,
|
||||
): void {
|
||||
if (__DEV__) {
|
||||
warningWithoutStack(
|
||||
callback === null || typeof callback === 'function',
|
||||
'%s(...): Expected the last optional `callback` argument to be a ' +
|
||||
'function. Instead received: %s.',
|
||||
callerName,
|
||||
callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function warnIfReactDOMContainerInDEV(container) {
|
||||
if (__DEV__) {
|
||||
if (isContainerMarkedAsRoot(container)) {
|
||||
if (container._reactRootContainer) {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'You are calling ReactDOM.createRoot() on a container that was previously ' +
|
||||
'passed to ReactDOM.render(). This is not supported.',
|
||||
);
|
||||
} else {
|
||||
warningWithoutStack(
|
||||
false,
|
||||
'You are calling ReactDOM.createRoot() on a container that ' +
|
||||
'has already been passed to createRoot() before. Instead, call ' +
|
||||
'root.render() on the existing root instead if you want to update it.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ import {REACT_FRAGMENT_TYPE, REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
|
|||
import enqueueTask from 'shared/enqueueTask';
|
||||
import ReactSharedInternals from 'shared/ReactSharedInternals';
|
||||
import warningWithoutStack from 'shared/warningWithoutStack';
|
||||
import {ConcurrentRoot, BatchedRoot, LegacyRoot} from 'shared/ReactRootTags';
|
||||
import {ConcurrentRoot, BlockingRoot, LegacyRoot} from 'shared/ReactRootTags';
|
||||
|
||||
type Container = {
|
||||
rootID: string,
|
||||
|
@ -952,7 +952,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
|
|||
};
|
||||
const fiberRoot = NoopRenderer.createContainer(
|
||||
container,
|
||||
BatchedRoot,
|
||||
BlockingRoot,
|
||||
false,
|
||||
null,
|
||||
);
|
||||
|
|
|
@ -36,7 +36,7 @@ import {
|
|||
enableScopeAPI,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
import {NoEffect, Placement} from 'shared/ReactSideEffectTags';
|
||||
import {ConcurrentRoot, BatchedRoot} from 'shared/ReactRootTags';
|
||||
import {ConcurrentRoot, BlockingRoot} from 'shared/ReactRootTags';
|
||||
import {
|
||||
IndeterminateComponent,
|
||||
ClassComponent,
|
||||
|
@ -574,7 +574,7 @@ export function createHostRootFiber(tag: RootTag): Fiber {
|
|||
let mode;
|
||||
if (tag === ConcurrentRoot) {
|
||||
mode = ConcurrentMode | BlockingMode | StrictMode;
|
||||
} else if (tag === BatchedRoot) {
|
||||
} else if (tag === BlockingRoot) {
|
||||
mode = BlockingMode | StrictMode;
|
||||
} else {
|
||||
mode = NoMode;
|
||||
|
|
|
@ -10,5 +10,5 @@
|
|||
export type RootTag = 0 | 1 | 2;
|
||||
|
||||
export const LegacyRoot = 0;
|
||||
export const BatchedRoot = 1;
|
||||
export const BlockingRoot = 1;
|
||||
export const ConcurrentRoot = 2;
|
||||
|
|
Loading…
Reference in New Issue