Gate legacy hidden (#24047)
* Gate legacy hidden * Gate tests * Remove export from experimental
Sebastian Markbåge committed
Mar 9, 2022 at 11:48 UTC
72a933d2892dac9e5327678b6bd37af8d589bb22
29 files changed
+175
-136
packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js
+2
-2
@@ -3197,7 +3197,7 @@ describe('ReactDOMServerPartialHydration', () => {
3197
expect(span.innerHTML).toBe('Hidden child');
3198
});
3199
3200
- // @gate experimental || www
3200
+ // @gate www
3201
it('renders a hidden LegacyHidden component inside a Suspense boundary', async () => {
3202
const ref = React.createRef();
3203
@@ -3225,7 +3225,7 @@ describe('ReactDOMServerPartialHydration', () => {
3225
expect(span.innerHTML).toBe('Hidden child');
3226
});
3227
3228
- // @gate experimental || www
3228
+ // @gate www
3229
it('renders a visible LegacyHidden component', async () => {
3230
const ref = React.createRef();
3231
packages/react-dom/src/__tests__/ReactUpdates-test.js
+1
-1
@@ -1302,7 +1302,7 @@ describe('ReactUpdates', () => {
1302
expect(ops).toEqual(['Foo', 'Bar', 'Baz']);
1303
});
1304
1305
- // @gate experimental || www
1305
+ // @gate www
1306
it('delays sync updates inside hidden subtrees in Concurrent Mode', () => {
1307
const container = document.createElement('div');
1308
packages/react-reconciler/src/ReactFiber.new.js
+5
-1
@@ -23,6 +23,7 @@ import {
23
enableStrictEffects,
24
enableProfilerTimer,
25
enableScopeAPI,
26
+ enableLegacyHidden,
27
enableSyncDefaultUpdates,
28
allowConcurrentByDefault,
29
enableTransitionTracing,
@@ -510,7 +511,10 @@ export function createFiberFromTypeAndProps(
511
case REACT_OFFSCREEN_TYPE:
512
return createFiberFromOffscreen(pendingProps, mode, lanes, key);
513
case REACT_LEGACY_HIDDEN_TYPE:
513
- return createFiberFromLegacyHidden(pendingProps, mode, lanes, key);
514
+ if (enableLegacyHidden) {
515
+ return createFiberFromLegacyHidden(pendingProps, mode, lanes, key);
516
+ }
517
+ // eslint-disable-next-line no-fallthrough
518
case REACT_SCOPE_TYPE:
519
if (enableScopeAPI) {
520
return createFiberFromScope(type, pendingProps, mode, lanes, key);
packages/react-reconciler/src/ReactFiber.old.js
+5
-1
@@ -23,6 +23,7 @@ import {
23
enableStrictEffects,
24
enableProfilerTimer,
25
enableScopeAPI,
26
+ enableLegacyHidden,
27
enableSyncDefaultUpdates,
28
allowConcurrentByDefault,
29
enableTransitionTracing,
@@ -510,7 +511,10 @@ export function createFiberFromTypeAndProps(
511
case REACT_OFFSCREEN_TYPE:
512
return createFiberFromOffscreen(pendingProps, mode, lanes, key);
513
case REACT_LEGACY_HIDDEN_TYPE:
513
- return createFiberFromLegacyHidden(pendingProps, mode, lanes, key);
514
+ if (enableLegacyHidden) {
515
+ return createFiberFromLegacyHidden(pendingProps, mode, lanes, key);
516
+ }
517
+ // eslint-disable-next-line no-fallthrough
518
case REACT_SCOPE_TYPE:
519
if (enableScopeAPI) {
520
return createFiberFromScope(type, pendingProps, mode, lanes, key);
packages/react-reconciler/src/ReactFiberBeginWork.new.js
+11
-3
@@ -98,6 +98,7 @@ import {
98
enableSchedulingProfiler,
99
enablePersistentOffscreenHostContainer,
100
enableTransitionTracing,
101
+ enableLegacyHidden,
102
} from 'shared/ReactFeatureFlags';
103
import isArray from 'shared/isArray';
104
import shallowEqual from 'shared/shallowEqual';
@@ -640,7 +641,7 @@ function updateOffscreenComponent(
641
642
if (
643
nextProps.mode === 'hidden' ||
643
- nextProps.mode === 'unstable-defer-without-hiding'
644
+ (enableLegacyHidden && nextProps.mode === 'unstable-defer-without-hiding')
645
) {
646
// Rendering a hidden tree.
647
if ((workInProgress.mode & ConcurrentMode) === NoMode) {
@@ -774,7 +775,7 @@ function updateOffscreenComponent(
775
// or some other infra that expects a HostComponent.
776
const isHidden =
777
nextProps.mode === 'hidden' &&
777
- workInProgress.tag !== LegacyHiddenComponent;
778
+ (!enableLegacyHidden || workInProgress.tag !== LegacyHiddenComponent);
779
const offscreenContainer = reconcileOffscreenHostContainer(
780
current,
781
workInProgress,
@@ -3948,7 +3949,14 @@ function beginWork(
3949
return updateOffscreenComponent(current, workInProgress, renderLanes);
3950
}
3951
case LegacyHiddenComponent: {
3951
- return updateLegacyHiddenComponent(current, workInProgress, renderLanes);
3952
+ if (enableLegacyHidden) {
3953
+ return updateLegacyHiddenComponent(
3954
+ current,
3955
+ workInProgress,
3956
+ renderLanes,
3957
+ );
3958
+ }
3959
+ break;
3960
}
3961
case CacheComponent: {
3962
if (enableCache) {
packages/react-reconciler/src/ReactFiberBeginWork.old.js
+11
-3
@@ -98,6 +98,7 @@ import {
98
enableSchedulingProfiler,
99
enablePersistentOffscreenHostContainer,
100
enableTransitionTracing,
101
+ enableLegacyHidden,
102
} from 'shared/ReactFeatureFlags';
103
import isArray from 'shared/isArray';
104
import shallowEqual from 'shared/shallowEqual';
@@ -640,7 +641,7 @@ function updateOffscreenComponent(
641
642
if (
643
nextProps.mode === 'hidden' ||
643
- nextProps.mode === 'unstable-defer-without-hiding'
644
+ (enableLegacyHidden && nextProps.mode === 'unstable-defer-without-hiding')
645
) {
646
// Rendering a hidden tree.
647
if ((workInProgress.mode & ConcurrentMode) === NoMode) {
@@ -774,7 +775,7 @@ function updateOffscreenComponent(
775
// or some other infra that expects a HostComponent.
776
const isHidden =
777
nextProps.mode === 'hidden' &&
777
- workInProgress.tag !== LegacyHiddenComponent;
778
+ (!enableLegacyHidden || workInProgress.tag !== LegacyHiddenComponent);
779
const offscreenContainer = reconcileOffscreenHostContainer(
780
current,
781
workInProgress,
@@ -3948,7 +3949,14 @@ function beginWork(
3949
return updateOffscreenComponent(current, workInProgress, renderLanes);
3950
}
3951
case LegacyHiddenComponent: {
3951
- return updateLegacyHiddenComponent(current, workInProgress, renderLanes);
3952
+ if (enableLegacyHidden) {
3953
+ return updateLegacyHiddenComponent(
3954
+ current,
3955
+ workInProgress,
3956
+ renderLanes,
3957
+ );
3958
+ }
3959
+ break;
3960
}
3961
case CacheComponent: {
3962
if (enableCache) {
packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+5
-5
@@ -32,6 +32,7 @@ import type {Cache} from './ReactFiberCacheComponent.new';
32
import {
33
enableClientRenderFallbackOnHydrationMismatch,
34
enableSuspenseAvoidThisFallback,
35
+ enableLegacyHidden,
36
} from 'shared/ReactFeatureFlags';
37
38
import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.new';
@@ -1499,9 +1500,8 @@ function completeWork(
1500
const prevIsHidden = prevState !== null;
1501
if (
1502
prevIsHidden !== nextIsHidden &&
1502
- newProps.mode !== 'unstable-defer-without-hiding' &&
1503
// LegacyHidden doesn't do any hiding — it only pre-renders.
1504
- workInProgress.tag !== LegacyHiddenComponent
1504
+ (!enableLegacyHidden || workInProgress.tag !== LegacyHiddenComponent)
1505
) {
1506
workInProgress.flags |= Visibility;
1507
}
@@ -1519,9 +1519,9 @@ function completeWork(
1519
// If so, we need to hide those nodes in the commit phase, so
1520
// schedule a visibility effect.
1521
if (
1522
- workInProgress.tag !== LegacyHiddenComponent &&
1523
- workInProgress.subtreeFlags & (Placement | Update) &&
1524
- newProps.mode !== 'unstable-defer-without-hiding'
1522
+ (!enableLegacyHidden ||
1523
+ workInProgress.tag !== LegacyHiddenComponent) &&
1524
+ workInProgress.subtreeFlags & (Placement | Update)
1525
) {
1526
workInProgress.flags |= Visibility;
1527
}
packages/react-reconciler/src/ReactFiberCompleteWork.old.js
+5
-5
@@ -32,6 +32,7 @@ import type {Cache} from './ReactFiberCacheComponent.old';
32
import {
33
enableClientRenderFallbackOnHydrationMismatch,
34
enableSuspenseAvoidThisFallback,
35
+ enableLegacyHidden,
36
} from 'shared/ReactFeatureFlags';
37
38
import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.old';
@@ -1499,9 +1500,8 @@ function completeWork(
1500
const prevIsHidden = prevState !== null;
1501
if (
1502
prevIsHidden !== nextIsHidden &&
1502
- newProps.mode !== 'unstable-defer-without-hiding' &&
1503
// LegacyHidden doesn't do any hiding — it only pre-renders.
1504
- workInProgress.tag !== LegacyHiddenComponent
1504
+ (!enableLegacyHidden || workInProgress.tag !== LegacyHiddenComponent)
1505
) {
1506
workInProgress.flags |= Visibility;
1507
}
@@ -1519,9 +1519,9 @@ function completeWork(
1519
// If so, we need to hide those nodes in the commit phase, so
1520
// schedule a visibility effect.
1521
if (
1522
- workInProgress.tag !== LegacyHiddenComponent &&
1523
- workInProgress.subtreeFlags & (Placement | Update) &&
1524
- newProps.mode !== 'unstable-defer-without-hiding'
1522
+ (!enableLegacyHidden ||
1523
+ workInProgress.tag !== LegacyHiddenComponent) &&
1524
+ workInProgress.subtreeFlags & (Placement | Update)
1525
) {
1526
workInProgress.flags |= Visibility;
1527
}
packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js
+3
-3
@@ -546,7 +546,7 @@ describe('ReactLazyContextPropagation', () => {
546
expect(root).toMatchRenderedOutput('BB');
547
});
548
549
- // @gate experimental || www
549
+ // @gate www
550
test('context is propagated through offscreen trees', async () => {
551
const LegacyHidden = React.unstable_LegacyHidden;
552
@@ -592,7 +592,7 @@ describe('ReactLazyContextPropagation', () => {
592
expect(root).toMatchRenderedOutput('BB');
593
});
594
595
- // @gate experimental || www
595
+ // @gate www
596
test('multiple contexts are propagated across through offscreen trees', async () => {
597
// Same as previous test, but with multiple context providers
598
const LegacyHidden = React.unstable_LegacyHidden;
@@ -818,7 +818,7 @@ describe('ReactLazyContextPropagation', () => {
818
expect(root).toMatchRenderedOutput('BB');
819
});
820
821
- // @gate experimental || www
821
+ // @gate www
822
test('nested bailouts through offscreen trees', async () => {
823
// Lazy context propagation will stop propagating when it hits the first
824
// match. If we bail out again inside that tree, we must resume propagating.
packages/react-reconciler/src/__tests__/ReactIncremental-test.js
+3
-3
@@ -270,7 +270,7 @@ describe('ReactIncremental', () => {
270
expect(inst.state).toEqual({text: 'bar', text2: 'baz'});
271
});
272
273
- // @gate experimental || www
273
+ // @gate www
274
it('can deprioritize unfinished work and resume it later', () => {
275
function Bar(props) {
276
Scheduler.unstable_yieldValue('Bar');
@@ -316,7 +316,7 @@ describe('ReactIncremental', () => {
316
expect(Scheduler).toFlushAndYield(['Middle', 'Middle']);
317
});
318
319
- // @gate experimental || www
319
+ // @gate www
320
it('can deprioritize a tree from without dropping work', () => {
321
function Bar(props) {
322
Scheduler.unstable_yieldValue('Bar');
@@ -1999,7 +1999,7 @@ describe('ReactIncremental', () => {
1999
});
2000
}
2001
2002
- // @gate experimental || www
2002
+ // @gate www
2003
it('provides context when reusing work', () => {
2004
class Intl extends React.Component {
2005
static childContextTypes = {
packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js
+1
-1
@@ -310,7 +310,7 @@ describe('ReactIncrementalErrorHandling', () => {
310
expect(ReactNoop.getChildren()).toEqual([span('Everything is fine.')]);
311
});
312
313
- // @gate experimental || www
313
+ // @gate www
314
it('does not include offscreen work when retrying after an error', () => {
315
function App(props) {
316
if (props.isBroken) {
packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js
+5
-5
@@ -424,7 +424,7 @@ describe('ReactIncrementalSideEffects', () => {
424
]);
425
});
426
427
- // @gate experimental || www
427
+ // @gate www
428
it('preserves a previously rendered node when deprioritized', () => {
429
function Middle(props) {
430
Scheduler.unstable_yieldValue('Middle');
@@ -475,7 +475,7 @@ describe('ReactIncrementalSideEffects', () => {
475
);
476
});
477
478
- // @gate experimental || www
478
+ // @gate www
479
it('can reuse side-effects after being preempted', () => {
480
function Bar(props) {
481
Scheduler.unstable_yieldValue('Bar');
@@ -555,7 +555,7 @@ describe('ReactIncrementalSideEffects', () => {
555
);
556
});
557
558
- // @gate experimental || www
558
+ // @gate www
559
it('can reuse side-effects after being preempted, if shouldComponentUpdate is false', () => {
560
class Bar extends React.Component {
561
shouldComponentUpdate(nextProps) {
@@ -690,7 +690,7 @@ describe('ReactIncrementalSideEffects', () => {
690
expect(ReactNoop.getChildrenAsJSX()).toEqual(<span prop={3} />);
691
});
692
693
- // @gate experimental || www
693
+ // @gate www
694
it('updates a child even though the old props is empty', () => {
695
function Foo(props) {
696
return (
@@ -930,7 +930,7 @@ describe('ReactIncrementalSideEffects', () => {
930
expect(ops).toEqual(['Bar', 'Baz', 'Bar', 'Bar']);
931
});
932
933
- // @gate experimental || www
933
+ // @gate www
934
it('deprioritizes setStates that happens within a deprioritized tree', () => {
935
const barInstances = [];
936
packages/react-reconciler/src/__tests__/ReactNewContext-test.js
+1
-1
@@ -667,7 +667,7 @@ describe('ReactNewContext', () => {
667
expect(ReactNoop.getChildren()).toEqual([span(2), span(2)]);
668
});
669
670
- // @gate experimental || www
670
+ // @gate www
671
it("context consumer doesn't bail out inside hidden subtree", () => {
672
const Context = React.createContext('dark');
673
const Consumer = getConsumer(Context);
packages/react-reconciler/src/__tests__/ReactOffscreen-test.js
+4
-4
@@ -26,7 +26,7 @@ describe('ReactOffscreen', () => {
26
return <span prop={props.text} />;
27
}
28
29
- // @gate experimental || www
29
+ // @gate www
30
it('unstable-defer-without-hiding should never toggle the visibility of its children', async () => {
31
function App({mode}) {
32
return (
@@ -85,7 +85,7 @@ describe('ReactOffscreen', () => {
85
);
86
});
87
88
- // @gate experimental || www
88
+ // @gate www
89
it('does not defer in legacy mode', async () => {
90
let setState;
91
function Foo() {
@@ -130,7 +130,7 @@ describe('ReactOffscreen', () => {
130
);
131
});
132
133
- // @gate experimental || www
133
+ // @gate www
134
it('does defer in concurrent mode', async () => {
135
let setState;
136
function Foo() {
@@ -310,7 +310,7 @@ describe('ReactOffscreen', () => {
310
expect(root).toMatchRenderedOutput(<span hidden={true} prop="Child" />);
311
});
312
313
- // @gate experimental || www
313
+ // @gate www
314
it('does not toggle effects for LegacyHidden component', async () => {
315
// LegacyHidden is meant to be the same as offscreen except it doesn't
316
// do anything to effects. Only used by www, as a temporary migration step.
packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.js
+1
-1
@@ -122,7 +122,7 @@ describe('ReactSchedulerIntegration', () => {
122
expect(Scheduler).toHaveYielded(['A', 'B', 'C']);
123
});
124
125
- // @gate experimental || www
125
+ // @gate www
126
it('idle updates are not blocked by offscreen work', async () => {
127
function Text({text}) {
128
Scheduler.unstable_yieldValue(text);
packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js
+2
-2
@@ -3073,7 +3073,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3073
expect(root).toMatchRenderedOutput(<span prop="Foo" />);
3074
});
3075
3076
- // @gate enableCache
3076
+ // @gate enableCache && enableLegacyHidden
3077
it('should not render hidden content while suspended on higher pri', async () => {
3078
function Offscreen() {
3079
Scheduler.unstable_yieldValue('Offscreen');
@@ -3123,7 +3123,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
3123
);
3124
});
3125
3126
- // @gate enableCache
3126
+ // @gate enableCache && enableLegacyHidden
3127
it('should be able to unblock higher pri content before suspended hidden', async () => {
3128
function Offscreen() {
3129
Scheduler.unstable_yieldValue('Offscreen');
packages/react-reconciler/src/getComponentNameFromFiber.js
+6
-2
@@ -9,6 +9,8 @@
9
10
import type {ReactContext, ReactProviderType} from 'shared/ReactTypes';
11
12
+import {enableLegacyHidden} from 'shared/ReactFeatureFlags';
13
+
14
import {
15
FunctionComponent,
16
ClassComponent,
@@ -86,8 +88,6 @@ export default function getComponentNameFromFiber(fiber: Fiber): string | null {
88
case LazyComponent:
89
// Name comes from the type in this case; we don't have a tag.
90
return getComponentNameFromType(type);
89
- case LegacyHiddenComponent:
90
- return 'LegacyHidden';
91
case Mode:
92
if (type === REACT_STRICT_MODE_TYPE) {
93
// Don't be less specific than shared/getComponentNameFromType
@@ -120,6 +120,10 @@ export default function getComponentNameFromFiber(fiber: Fiber): string | null {
120
return type;
121
}
122
break;
123
+ case LegacyHiddenComponent:
124
+ if (enableLegacyHidden) {
125
+ return 'LegacyHidden';
126
+ }
127
}
128
129
return null;
packages/react-refresh/src/__tests__/ReactFresh-test.js
+90
-91
@@ -2411,107 +2411,106 @@ describe('ReactFresh', () => {
2411
}
2412
});
2413
2414
+ // @gate www && __DEV__
2415
it('can hot reload offscreen components', async () => {
2415
- if (__DEV__ && __EXPERIMENTAL__) {
2416
- const AppV1 = prepare(() => {
2417
- function Hello() {
2418
- React.useLayoutEffect(() => {
2419
- Scheduler.unstable_yieldValue('Hello#layout');
2420
- });
2421
- const [val, setVal] = React.useState(0);
2422
- return (
2423
- <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
2424
- {val}
2425
- </p>
2426
- );
2427
- }
2428
- $RefreshReg$(Hello, 'Hello');
2429
-
2430
- return function App({offscreen}) {
2431
- React.useLayoutEffect(() => {
2432
- Scheduler.unstable_yieldValue('App#layout');
2433
- });
2434
- return (
2435
- <LegacyHiddenDiv mode={offscreen ? 'hidden' : 'visible'}>
2436
- <Hello />
2437
- </LegacyHiddenDiv>
2438
- );
2439
- };
2440
- });
2416
+ const AppV1 = prepare(() => {
2417
+ function Hello() {
2418
+ React.useLayoutEffect(() => {
2419
+ Scheduler.unstable_yieldValue('Hello#layout');
2420
+ });
2421
+ const [val, setVal] = React.useState(0);
2422
+ return (
2423
+ <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
2424
+ {val}
2425
+ </p>
2426
+ );
2427
+ }
2428
+ $RefreshReg$(Hello, 'Hello');
2429
2442
- const root = ReactDOMClient.createRoot(container);
2443
- root.render(<AppV1 offscreen={true} />);
2444
- expect(Scheduler).toFlushAndYieldThrough(['App#layout']);
2445
- const el = container.firstChild;
2446
- expect(el.hidden).toBe(true);
2447
- expect(el.firstChild).toBe(null); // Offscreen content not flushed yet.
2430
+ return function App({offscreen}) {
2431
+ React.useLayoutEffect(() => {
2432
+ Scheduler.unstable_yieldValue('App#layout');
2433
+ });
2434
+ return (
2435
+ <LegacyHiddenDiv mode={offscreen ? 'hidden' : 'visible'}>
2436
+ <Hello />
2437
+ </LegacyHiddenDiv>
2438
+ );
2439
+ };
2440
+ });
2441
2449
- // Perform a hot update.
2450
- patch(() => {
2451
- function Hello() {
2452
- React.useLayoutEffect(() => {
2453
- Scheduler.unstable_yieldValue('Hello#layout');
2454
- });
2455
- const [val, setVal] = React.useState(0);
2456
- return (
2457
- <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
2458
- {val}
2459
- </p>
2460
- );
2461
- }
2462
- $RefreshReg$(Hello, 'Hello');
2463
- });
2442
+ const root = ReactDOMClient.createRoot(container);
2443
+ root.render(<AppV1 offscreen={true} />);
2444
+ expect(Scheduler).toFlushAndYieldThrough(['App#layout']);
2445
+ const el = container.firstChild;
2446
+ expect(el.hidden).toBe(true);
2447
+ expect(el.firstChild).toBe(null); // Offscreen content not flushed yet.
2448
2465
- // It's still offscreen so we don't see anything.
2466
- expect(container.firstChild).toBe(el);
2467
- expect(el.hidden).toBe(true);
2468
- expect(el.firstChild).toBe(null);
2449
+ // Perform a hot update.
2450
+ patch(() => {
2451
+ function Hello() {
2452
+ React.useLayoutEffect(() => {
2453
+ Scheduler.unstable_yieldValue('Hello#layout');
2454
+ });
2455
+ const [val, setVal] = React.useState(0);
2456
+ return (
2457
+ <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
2458
+ {val}
2459
+ </p>
2460
+ );
2461
+ }
2462
+ $RefreshReg$(Hello, 'Hello');
2463
+ });
2464
2470
- // Process the offscreen updates.
2471
- expect(Scheduler).toFlushAndYieldThrough(['Hello#layout']);
2472
- expect(container.firstChild).toBe(el);
2473
- expect(el.firstChild.textContent).toBe('0');
2474
- expect(el.firstChild.style.color).toBe('red');
2465
+ // It's still offscreen so we don't see anything.
2466
+ expect(container.firstChild).toBe(el);
2467
+ expect(el.hidden).toBe(true);
2468
+ expect(el.firstChild).toBe(null);
2469
2476
- await act(async () => {
2477
- el.firstChild.dispatchEvent(
2478
- new MouseEvent('click', {
2479
- bubbles: true,
2480
- }),
2481
- );
2482
- });
2470
+ // Process the offscreen updates.
2471
+ expect(Scheduler).toFlushAndYieldThrough(['Hello#layout']);
2472
+ expect(container.firstChild).toBe(el);
2473
+ expect(el.firstChild.textContent).toBe('0');
2474
+ expect(el.firstChild.style.color).toBe('red');
2475
+
2476
+ await act(async () => {
2477
+ el.firstChild.dispatchEvent(
2478
+ new MouseEvent('click', {
2479
+ bubbles: true,
2480
+ }),
2481
+ );
2482
+ });
2483
2484
- expect(Scheduler).toHaveYielded(['Hello#layout']);
2485
- expect(el.firstChild.textContent).toBe('1');
2486
- expect(el.firstChild.style.color).toBe('red');
2484
+ expect(Scheduler).toHaveYielded(['Hello#layout']);
2485
+ expect(el.firstChild.textContent).toBe('1');
2486
+ expect(el.firstChild.style.color).toBe('red');
2487
2488
- // Hot reload while we're offscreen.
2489
- patch(() => {
2490
- function Hello() {
2491
- React.useLayoutEffect(() => {
2492
- Scheduler.unstable_yieldValue('Hello#layout');
2493
- });
2494
- const [val, setVal] = React.useState(0);
2495
- return (
2496
- <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
2497
- {val}
2498
- </p>
2499
- );
2500
- }
2501
- $RefreshReg$(Hello, 'Hello');
2502
- });
2488
+ // Hot reload while we're offscreen.
2489
+ patch(() => {
2490
+ function Hello() {
2491
+ React.useLayoutEffect(() => {
2492
+ Scheduler.unstable_yieldValue('Hello#layout');
2493
+ });
2494
+ const [val, setVal] = React.useState(0);
2495
+ return (
2496
+ <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
2497
+ {val}
2498
+ </p>
2499
+ );
2500
+ }
2501
+ $RefreshReg$(Hello, 'Hello');
2502
+ });
2503
2504
- // It's still offscreen so we don't see the updates.
2505
- expect(container.firstChild).toBe(el);
2506
- expect(el.firstChild.textContent).toBe('1');
2507
- expect(el.firstChild.style.color).toBe('red');
2504
+ // It's still offscreen so we don't see the updates.
2505
+ expect(container.firstChild).toBe(el);
2506
+ expect(el.firstChild.textContent).toBe('1');
2507
+ expect(el.firstChild.style.color).toBe('red');
2508
2509
- // Process the offscreen updates.
2510
- expect(Scheduler).toFlushAndYieldThrough(['Hello#layout']);
2511
- expect(container.firstChild).toBe(el);
2512
- expect(el.firstChild.textContent).toBe('1');
2513
- expect(el.firstChild.style.color).toBe('orange');
2514
- }
2509
+ // Process the offscreen updates.
2510
+ expect(Scheduler).toFlushAndYieldThrough(['Hello#layout']);
2511
+ expect(container.firstChild).toBe(el);
2512
+ expect(el.firstChild.textContent).toBe('1');
2513
+ expect(el.firstChild.style.color).toBe('orange');
2514
});
2515
2516
it('remounts failed error boundaries (componentDidCatch)', () => {
packages/react/index.experimental.js
-1
@@ -32,7 +32,6 @@ export {
32
startTransition,
33
unstable_Cache,
34
unstable_DebugTracingMode,
35
- unstable_LegacyHidden,
35
unstable_Offscreen,
36
unstable_getCacheSignal,
37
unstable_getCacheForType,
packages/shared/ReactFeatureFlags.js
+3
@@ -101,6 +101,9 @@ export const enableTransitionTracing = false;
101
// No known bugs, but needs performance testing
102
export const enableLazyContextPropagation = false;
103
104
+// FB-only usage. The new API has different semantics.
105
+export const enableLegacyHidden = false;
106
+
107
// Enables unstable_avoidThisFallback feature in Fiber
108
export const enableSuspenseAvoidThisFallback = false;
109
// Enables unstable_avoidThisFallback feature in Fizz
packages/shared/forks/ReactFeatureFlags.native-fb.js
+1
@@ -70,6 +70,7 @@ export const enableUseRefAccessWarning = false;
70
71
export const disableSchedulerTimeoutInWorkLoop = false;
72
export const enableLazyContextPropagation = false;
73
+export const enableLegacyHidden = true;
74
export const enableSyncDefaultUpdates = true;
75
export const allowConcurrentByDefault = true;
76
export const enableCustomElementPropertySupport = false;
packages/shared/forks/ReactFeatureFlags.native-oss.js
+1
@@ -61,6 +61,7 @@ export const enableUseRefAccessWarning = false;
61
62
export const disableSchedulerTimeoutInWorkLoop = false;
63
export const enableLazyContextPropagation = false;
64
+export const enableLegacyHidden = false;
65
export const enableSyncDefaultUpdates = true;
66
export const allowConcurrentByDefault = false;
67
export const enablePersistentOffscreenHostContainer = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+1
@@ -61,6 +61,7 @@ export const enableUseRefAccessWarning = false;
61
62
export const disableSchedulerTimeoutInWorkLoop = false;
63
export const enableLazyContextPropagation = false;
64
+export const enableLegacyHidden = false;
65
export const enableSyncDefaultUpdates = true;
66
export const allowConcurrentByDefault = false;
67
export const enablePersistentOffscreenHostContainer = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
+1
@@ -60,6 +60,7 @@ export const enableUseRefAccessWarning = false;
60
61
export const disableSchedulerTimeoutInWorkLoop = false;
62
export const enableLazyContextPropagation = false;
63
+export const enableLegacyHidden = false;
64
export const enableSyncDefaultUpdates = true;
65
export const allowConcurrentByDefault = true;
66
export const enablePersistentOffscreenHostContainer = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+1
@@ -61,6 +61,7 @@ export const enableUseRefAccessWarning = false;
61
62
export const disableSchedulerTimeoutInWorkLoop = false;
63
export const enableLazyContextPropagation = false;
64
+export const enableLegacyHidden = false;
65
export const enableSyncDefaultUpdates = true;
66
export const allowConcurrentByDefault = true;
67
export const enablePersistentOffscreenHostContainer = false;
packages/shared/forks/ReactFeatureFlags.testing.js
+1
@@ -61,6 +61,7 @@ export const enableUseRefAccessWarning = false;
61
62
export const disableSchedulerTimeoutInWorkLoop = false;
63
export const enableLazyContextPropagation = false;
64
+export const enableLegacyHidden = false;
65
export const enableSyncDefaultUpdates = true;
66
export const allowConcurrentByDefault = false;
67
export const enablePersistentOffscreenHostContainer = false;
packages/shared/forks/ReactFeatureFlags.testing.www.js
+1
@@ -61,6 +61,7 @@ export const enableUseRefAccessWarning = false;
61
62
export const disableSchedulerTimeoutInWorkLoop = false;
63
export const enableLazyContextPropagation = false;
64
+export const enableLegacyHidden = false;
65
export const enableSyncDefaultUpdates = true;
66
export const allowConcurrentByDefault = true;
67
export const enablePersistentOffscreenHostContainer = false;
packages/shared/forks/ReactFeatureFlags.www.js
+2
@@ -86,6 +86,8 @@ export const enableScopeAPI = true;
86
87
export const enableSuspenseCallback = true;
88
89
+export const enableLegacyHidden = true;
90
+
91
export const enableComponentStackLocations = true;
92
93
export const disableTextareaChildren = __EXPERIMENTAL__;
packages/shared/isValidElementType.js
+2
-1
@@ -30,6 +30,7 @@ import {
30
enableCache,
31
enableTransitionTracing,
32
enableDebugTracing,
33
+ enableLegacyHidden,
34
} from './ReactFeatureFlags';
35
36
const REACT_MODULE_REFERENCE: Symbol = Symbol.for('react.module.reference');
@@ -47,7 +48,7 @@ export default function isValidElementType(type: mixed) {
48
type === REACT_STRICT_MODE_TYPE ||
49
type === REACT_SUSPENSE_TYPE ||
50
type === REACT_SUSPENSE_LIST_TYPE ||
50
- type === REACT_LEGACY_HIDDEN_TYPE ||
51
+ (enableLegacyHidden && type === REACT_LEGACY_HIDDEN_TYPE) ||
52
type === REACT_OFFSCREEN_TYPE ||
53
(enableScopeAPI && type === REACT_SCOPE_TYPE) ||
54
(enableCache && type === REACT_CACHE_TYPE) ||