@samitouri / QOS-React / commits / 72a933d289

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) ||