Test suspended children are hidden before layout in persistent mode (#15030)
Refs behave differently in persistent mode, so instead of a ref, the persistent mode version of this test asserts on the output of the host tree.
This commit is contained in:
parent
bc8bd24c14
commit
6a4a261ee8
|
@ -32,6 +32,7 @@ type Thenable = {
|
|||
type Container = {
|
||||
rootID: string,
|
||||
children: Array<Instance | TextInstance>,
|
||||
pendingChildren: Array<Instance | TextInstance>,
|
||||
};
|
||||
type Props = {prop: any, hidden: boolean, children?: mixed};
|
||||
type Instance = {|
|
||||
|
@ -457,7 +458,9 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
|
|||
finalizeContainerChildren(
|
||||
container: Container,
|
||||
newChildren: Array<Instance | TextInstance>,
|
||||
): void {},
|
||||
): void {
|
||||
container.pendingChildren = newChildren;
|
||||
},
|
||||
|
||||
replaceContainerChildren(
|
||||
container: Container,
|
||||
|
@ -581,13 +584,22 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
|
|||
}
|
||||
},
|
||||
|
||||
getPendingChildren(rootID: string = DEFAULT_ROOT_ID) {
|
||||
const container = rootContainers.get(rootID);
|
||||
if (container) {
|
||||
return container.pendingChildren;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
getOrCreateRootContainer(
|
||||
rootID: string = DEFAULT_ROOT_ID,
|
||||
isConcurrent: boolean = false,
|
||||
) {
|
||||
let root = roots.get(rootID);
|
||||
if (!root) {
|
||||
const container = {rootID: rootID, children: []};
|
||||
const container = {rootID: rootID, pendingChildren: [], children: []};
|
||||
rootContainers.set(rootID, container);
|
||||
root = NoopRenderer.createContainer(container, isConcurrent, false);
|
||||
roots.set(rootID, root);
|
||||
|
@ -614,6 +626,25 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
|
|||
return children;
|
||||
},
|
||||
|
||||
getPendingChildrenAsJSX(rootID: string = DEFAULT_ROOT_ID) {
|
||||
const children = childToJSX(ReactNoop.getPendingChildren(rootID), null);
|
||||
if (children === null) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(children)) {
|
||||
return {
|
||||
$$typeof: REACT_ELEMENT_TYPE,
|
||||
type: REACT_FRAGMENT_TYPE,
|
||||
key: null,
|
||||
ref: null,
|
||||
props: {children},
|
||||
_owner: null,
|
||||
_store: __DEV__ ? {} : undefined,
|
||||
};
|
||||
}
|
||||
return children;
|
||||
},
|
||||
|
||||
createPortal(
|
||||
children: ReactNodeList,
|
||||
container: Container,
|
||||
|
@ -778,7 +809,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
|
|||
// Trick to flush passive effects without exposing an internal API:
|
||||
// Create a throwaway root and schedule a dummy update on it.
|
||||
const rootID = 'bloopandthenmoreletterstoavoidaconflict';
|
||||
const container = {rootID: rootID, children: []};
|
||||
const container = {rootID: rootID, pendingChildren: [], children: []};
|
||||
rootContainers.set(rootID, container);
|
||||
const root = NoopRenderer.createContainer(container, true, false);
|
||||
NoopRenderer.updateContainer(null, root, null, null);
|
||||
|
|
|
@ -1387,9 +1387,50 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
expect(ReactNoop.getChildren()).toEqual([span('Hi')]);
|
||||
});
|
||||
|
||||
if (!global.__PERSISTENT__) {
|
||||
// TODO: Write persistent version of this test
|
||||
it('toggles visibility during the mutation phase', async () => {
|
||||
if (global.__PERSISTENT__) {
|
||||
it('hides/unhides suspended children before layout effects fire (persistent)', async () => {
|
||||
const {useRef, useLayoutEffect} = React;
|
||||
|
||||
function Parent() {
|
||||
const child = useRef(null);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
Scheduler.yieldValue(ReactNoop.getPendingChildrenAsJSX());
|
||||
});
|
||||
|
||||
return (
|
||||
<span ref={child} hidden={false}>
|
||||
<AsyncText ms={1000} text="Hi" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function App(props) {
|
||||
return (
|
||||
<Suspense fallback={<Text text="Loading..." />}>
|
||||
<Parent />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
ReactNoop.renderLegacySyncRoot(<App middleText="B" />);
|
||||
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Suspend! [Hi]',
|
||||
'Loading...',
|
||||
// The child should have already been hidden
|
||||
<React.Fragment>
|
||||
<span hidden={true} />
|
||||
<span prop="Loading..." />
|
||||
</React.Fragment>,
|
||||
]);
|
||||
|
||||
await advanceTimers(1000);
|
||||
|
||||
expect(Scheduler).toHaveYielded(['Promise resolved [Hi]', 'Hi']);
|
||||
});
|
||||
} else {
|
||||
it('hides/unhides suspended children before layout effects fire (mutation)', async () => {
|
||||
const {useRef, useLayoutEffect} = React;
|
||||
|
||||
function Parent() {
|
||||
|
|
Loading…
Reference in New Issue