Skip to content

Commit 88d6d34

Browse files
author
Brian Vaughn
committed
Replaced new root attribute with ClearContainer effect
1 parent fad4529 commit 88d6d34

17 files changed

Lines changed: 94 additions & 52 deletions

packages/react-art/src/ReactARTHostConfig.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,14 @@ export function unhideTextInstance(textInstance, text): void {
427427
// Noop
428428
}
429429

430+
export function clearContainer(container: Container): void {
431+
// TODO This doesn't work for anything other than SVG.
432+
// Is that okay?
433+
while (container.lastChild != null) {
434+
container.lastChild.eject();
435+
}
436+
}
437+
430438
export function DEPRECATED_mountResponderInstance(
431439
responder: ReactEventResponder<any, any>,
432440
responderInstance: ReactEventResponderInstance<any, any>,

packages/react-dom/src/client/ReactDOMRoot.js

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -123,20 +123,12 @@ function createRootImpl(
123123
(options != null && options.hydrationOptions) || null;
124124
const root = createContainer(container, tag, hydrate, hydrationCallbacks);
125125
markContainerAsRoot(root.current, container);
126-
if (hydrate) {
127-
if (tag !== LegacyRoot) {
128-
const doc =
129-
container.nodeType === DOCUMENT_NODE
130-
? container
131-
: container.ownerDocument;
132-
eagerlyTrapReplayableEvents(container, doc);
133-
}
134-
} else if (container.lastChild != null) {
135-
// If the container has children already and we aren't hydrating-
136-
// schedule them to be cleared before we mount new, React-managed children.
137-
// This mimics legacy render into subtree behavior in a way that is safe for concurrent mode.
138-
// (It doesn't result in multiple obsevable mutations.)
139-
root.clearContainerBeforeMount = true;
126+
if (hydrate && tag !== LegacyRoot) {
127+
const doc =
128+
container.nodeType === DOCUMENT_NODE
129+
? container
130+
: container.ownerDocument;
131+
eagerlyTrapReplayableEvents(container, doc);
140132
}
141133
return root;
142134
}

packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ describe('when Trusted Types are available in global object', () => {
7474
container,
7575
);
7676
expect(container.innerHTML).toBe('<div><b>Hi</b></div>');
77-
expect(innerHTMLCalls.length).toBe(1);
77+
// Second call to innerHTML is the ClearContainer check.
78+
expect(innerHTMLCalls.length).toBe(2);
7879
// Ensure it didn't get stringified when passed to a DOM sink:
7980
expect(innerHTMLCalls[0]).toBe(ttObject1);
8081

packages/react-native-renderer/src/ReactNativeHostConfig.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,11 @@ export function unhideInstance(instance: Instance, props: Props): void {
482482
);
483483
}
484484

485+
export function clearContainer(container: Container): void {
486+
// TODO Implement this for React Native
487+
// UIManager does not expose a "remove all" type method.
488+
}
489+
485490
export function unhideTextInstance(
486491
textInstance: TextInstance,
487492
text: string,

packages/react-noop-renderer/src/createReactNoop.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
155155
insertInContainerOrInstanceBefore(parentInstance, child, beforeChild);
156156
}
157157

158+
function clearContainer(container: Container): void {
159+
container.children.splice(0);
160+
}
161+
158162
function removeChildFromContainerOrInstance(
159163
parentInstance: Container | Instance,
160164
child: Instance | TextInstance,
@@ -502,6 +506,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
502506
insertInContainerBefore,
503507
removeChild,
504508
removeChildFromContainer,
509+
clearContainer,
505510

506511
hideInstance(instance: Instance): void {
507512
instance.hidden = true;
@@ -531,6 +536,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
531536
supportsPersistence: true,
532537

533538
cloneInstance,
539+
clearContainer,
534540

535541
createContainerChildSet(
536542
container: Container,

packages/react-reconciler/src/ReactFiberCommitWork.new.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import {
6868
Snapshot,
6969
Update,
7070
Passive,
71+
ClearContainer,
7172
} from './ReactSideEffectTags';
7273
import getComponentName from 'shared/getComponentName';
7374
import invariant from 'shared/invariant';
@@ -111,6 +112,7 @@ import {
111112
commitHydratedContainer,
112113
commitHydratedSuspenseInstance,
113114
beforeRemoveInstance,
115+
clearContainer,
114116
} from './ReactFiberHostConfig';
115117
import {
116118
captureCommitPhaseError,
@@ -293,7 +295,15 @@ function commitBeforeMutationLifeCycles(
293295
}
294296
return;
295297
}
296-
case HostRoot:
298+
case HostRoot: {
299+
if (supportsMutation) {
300+
if (finishedWork.effectTag & ClearContainer) {
301+
const root = finishedWork.stateNode;
302+
clearContainer(root.containerInfo);
303+
}
304+
}
305+
return;
306+
}
297307
case HostComponent:
298308
case HostText:
299309
case HostPortal:

packages/react-reconciler/src/ReactFiberCommitWork.old.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import {
6868
Snapshot,
6969
Update,
7070
Passive,
71+
ClearContainer,
7172
} from './ReactSideEffectTags';
7273
import getComponentName from 'shared/getComponentName';
7374
import invariant from 'shared/invariant';
@@ -111,6 +112,7 @@ import {
111112
commitHydratedContainer,
112113
commitHydratedSuspenseInstance,
113114
beforeRemoveInstance,
115+
clearContainer,
114116
} from './ReactFiberHostConfig';
115117
import {
116118
captureCommitPhaseError,
@@ -293,7 +295,15 @@ function commitBeforeMutationLifeCycles(
293295
}
294296
return;
295297
}
296-
case HostRoot:
298+
case HostRoot: {
299+
if (supportsMutation) {
300+
if (finishedWork.effectTag & ClearContainer) {
301+
const root = finishedWork.stateNode;
302+
clearContainer(root.containerInfo);
303+
}
304+
}
305+
return;
306+
}
297307
case HostComponent:
298308
case HostText:
299309
case HostPortal:

packages/react-reconciler/src/ReactFiberCompleteWork.new.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import {
6161
NoEffect,
6262
DidCapture,
6363
Deletion,
64+
ClearContainer,
6465
} from './ReactSideEffectTags';
6566
import invariant from 'shared/invariant';
6667

@@ -678,6 +679,12 @@ function completeWork(
678679
// If we hydrated, then we'll need to schedule an update for
679680
// the commit side-effects on the root.
680681
markUpdate(workInProgress);
682+
} else {
683+
// Schedule an effect to clear this container at the start of the next commit.
684+
// This handles the case of React rendering into a container with previous children.
685+
// It's also safe to do for updates too, because current.child would only be null
686+
// if the previous render was null (so the the container would already be empty).
687+
workInProgress.effectTag |= ClearContainer;
681688
}
682689
}
683690
updateHostContainer(workInProgress);

packages/react-reconciler/src/ReactFiberCompleteWork.old.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import {
6161
NoEffect,
6262
DidCapture,
6363
Deletion,
64+
ClearContainer,
6465
} from './ReactSideEffectTags';
6566
import invariant from 'shared/invariant';
6667

@@ -678,6 +679,12 @@ function completeWork(
678679
// If we hydrated, then we'll need to schedule an update for
679680
// the commit side-effects on the root.
680681
markUpdate(workInProgress);
682+
} else {
683+
// Schedule an effect to clear this container at the start of the next commit.
684+
// This handles the case of React rendering into a container with previous children.
685+
// It's also safe to do for updates too, because current.child would only be null
686+
// if the previous render was null (so the the container would already be empty).
687+
workInProgress.effectTag |= ClearContainer;
681688
}
682689
}
683690
updateHostContainer(workInProgress);

packages/react-reconciler/src/ReactFiberHostConfigWithNoMutation.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ export const hideInstance = shim;
3737
export const hideTextInstance = shim;
3838
export const unhideInstance = shim;
3939
export const unhideTextInstance = shim;
40+
export const clearContainer = shim;

0 commit comments

Comments
 (0)