diff --git a/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js index 7e25788c9232d..6d02211edffd0 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js @@ -3197,7 +3197,7 @@ describe('ReactDOMServerPartialHydration', () => { expect(span.innerHTML).toBe('Hidden child'); }); - // @gate experimental || www + // @gate www it('renders a hidden LegacyHidden component inside a Suspense boundary', async () => { const ref = React.createRef(); @@ -3225,7 +3225,7 @@ describe('ReactDOMServerPartialHydration', () => { expect(span.innerHTML).toBe('Hidden child'); }); - // @gate experimental || www + // @gate www it('renders a visible LegacyHidden component', async () => { const ref = React.createRef(); diff --git a/packages/react-dom/src/__tests__/ReactUpdates-test.js b/packages/react-dom/src/__tests__/ReactUpdates-test.js index 9e81a3b20ff1c..4fe596b9b7fb7 100644 --- a/packages/react-dom/src/__tests__/ReactUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactUpdates-test.js @@ -1302,7 +1302,7 @@ describe('ReactUpdates', () => { expect(ops).toEqual(['Foo', 'Bar', 'Baz']); }); - // @gate experimental || www + // @gate www it('delays sync updates inside hidden subtrees in Concurrent Mode', () => { const container = document.createElement('div'); diff --git a/packages/react-reconciler/src/ReactFiber.new.js b/packages/react-reconciler/src/ReactFiber.new.js index 977a3f67e03d2..1509d2201117d 100644 --- a/packages/react-reconciler/src/ReactFiber.new.js +++ b/packages/react-reconciler/src/ReactFiber.new.js @@ -23,6 +23,7 @@ import { enableStrictEffects, enableProfilerTimer, enableScopeAPI, + enableLegacyHidden, enableSyncDefaultUpdates, allowConcurrentByDefault, enableTransitionTracing, @@ -510,7 +511,10 @@ export function createFiberFromTypeAndProps( case REACT_OFFSCREEN_TYPE: return createFiberFromOffscreen(pendingProps, mode, lanes, key); case REACT_LEGACY_HIDDEN_TYPE: - return createFiberFromLegacyHidden(pendingProps, mode, lanes, key); + if (enableLegacyHidden) { + return createFiberFromLegacyHidden(pendingProps, mode, lanes, key); + } + // eslint-disable-next-line no-fallthrough case REACT_SCOPE_TYPE: if (enableScopeAPI) { return createFiberFromScope(type, pendingProps, mode, lanes, key); diff --git a/packages/react-reconciler/src/ReactFiber.old.js b/packages/react-reconciler/src/ReactFiber.old.js index 8999226fc22ef..ba9f5132b45ca 100644 --- a/packages/react-reconciler/src/ReactFiber.old.js +++ b/packages/react-reconciler/src/ReactFiber.old.js @@ -23,6 +23,7 @@ import { enableStrictEffects, enableProfilerTimer, enableScopeAPI, + enableLegacyHidden, enableSyncDefaultUpdates, allowConcurrentByDefault, enableTransitionTracing, @@ -510,7 +511,10 @@ export function createFiberFromTypeAndProps( case REACT_OFFSCREEN_TYPE: return createFiberFromOffscreen(pendingProps, mode, lanes, key); case REACT_LEGACY_HIDDEN_TYPE: - return createFiberFromLegacyHidden(pendingProps, mode, lanes, key); + if (enableLegacyHidden) { + return createFiberFromLegacyHidden(pendingProps, mode, lanes, key); + } + // eslint-disable-next-line no-fallthrough case REACT_SCOPE_TYPE: if (enableScopeAPI) { return createFiberFromScope(type, pendingProps, mode, lanes, key); diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.new.js b/packages/react-reconciler/src/ReactFiberBeginWork.new.js index 181d32febf917..4bae5d0b7b982 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.new.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.new.js @@ -98,6 +98,7 @@ import { enableSchedulingProfiler, enablePersistentOffscreenHostContainer, enableTransitionTracing, + enableLegacyHidden, } from 'shared/ReactFeatureFlags'; import isArray from 'shared/isArray'; import shallowEqual from 'shared/shallowEqual'; @@ -640,7 +641,7 @@ function updateOffscreenComponent( if ( nextProps.mode === 'hidden' || - nextProps.mode === 'unstable-defer-without-hiding' + (enableLegacyHidden && nextProps.mode === 'unstable-defer-without-hiding') ) { // Rendering a hidden tree. if ((workInProgress.mode & ConcurrentMode) === NoMode) { @@ -774,7 +775,7 @@ function updateOffscreenComponent( // or some other infra that expects a HostComponent. const isHidden = nextProps.mode === 'hidden' && - workInProgress.tag !== LegacyHiddenComponent; + (!enableLegacyHidden || workInProgress.tag !== LegacyHiddenComponent); const offscreenContainer = reconcileOffscreenHostContainer( current, workInProgress, @@ -3948,7 +3949,14 @@ function beginWork( return updateOffscreenComponent(current, workInProgress, renderLanes); } case LegacyHiddenComponent: { - return updateLegacyHiddenComponent(current, workInProgress, renderLanes); + if (enableLegacyHidden) { + return updateLegacyHiddenComponent( + current, + workInProgress, + renderLanes, + ); + } + break; } case CacheComponent: { if (enableCache) { diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.old.js b/packages/react-reconciler/src/ReactFiberBeginWork.old.js index 57a8f9c48fb1f..583539dd08b52 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.old.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.old.js @@ -98,6 +98,7 @@ import { enableSchedulingProfiler, enablePersistentOffscreenHostContainer, enableTransitionTracing, + enableLegacyHidden, } from 'shared/ReactFeatureFlags'; import isArray from 'shared/isArray'; import shallowEqual from 'shared/shallowEqual'; @@ -640,7 +641,7 @@ function updateOffscreenComponent( if ( nextProps.mode === 'hidden' || - nextProps.mode === 'unstable-defer-without-hiding' + (enableLegacyHidden && nextProps.mode === 'unstable-defer-without-hiding') ) { // Rendering a hidden tree. if ((workInProgress.mode & ConcurrentMode) === NoMode) { @@ -774,7 +775,7 @@ function updateOffscreenComponent( // or some other infra that expects a HostComponent. const isHidden = nextProps.mode === 'hidden' && - workInProgress.tag !== LegacyHiddenComponent; + (!enableLegacyHidden || workInProgress.tag !== LegacyHiddenComponent); const offscreenContainer = reconcileOffscreenHostContainer( current, workInProgress, @@ -3948,7 +3949,14 @@ function beginWork( return updateOffscreenComponent(current, workInProgress, renderLanes); } case LegacyHiddenComponent: { - return updateLegacyHiddenComponent(current, workInProgress, renderLanes); + if (enableLegacyHidden) { + return updateLegacyHiddenComponent( + current, + workInProgress, + renderLanes, + ); + } + break; } case CacheComponent: { if (enableCache) { diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js index 3ca22e58263e7..2a44cf94a14aa 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js @@ -32,6 +32,7 @@ import type {Cache} from './ReactFiberCacheComponent.new'; import { enableClientRenderFallbackOnHydrationMismatch, enableSuspenseAvoidThisFallback, + enableLegacyHidden, } from 'shared/ReactFeatureFlags'; import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.new'; @@ -1499,9 +1500,8 @@ function completeWork( const prevIsHidden = prevState !== null; if ( prevIsHidden !== nextIsHidden && - newProps.mode !== 'unstable-defer-without-hiding' && // LegacyHidden doesn't do any hiding — it only pre-renders. - workInProgress.tag !== LegacyHiddenComponent + (!enableLegacyHidden || workInProgress.tag !== LegacyHiddenComponent) ) { workInProgress.flags |= Visibility; } @@ -1519,9 +1519,9 @@ function completeWork( // If so, we need to hide those nodes in the commit phase, so // schedule a visibility effect. if ( - workInProgress.tag !== LegacyHiddenComponent && - workInProgress.subtreeFlags & (Placement | Update) && - newProps.mode !== 'unstable-defer-without-hiding' + (!enableLegacyHidden || + workInProgress.tag !== LegacyHiddenComponent) && + workInProgress.subtreeFlags & (Placement | Update) ) { workInProgress.flags |= Visibility; } diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js index bea755f7b4b6d..f02a20222d0fe 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js @@ -32,6 +32,7 @@ import type {Cache} from './ReactFiberCacheComponent.old'; import { enableClientRenderFallbackOnHydrationMismatch, enableSuspenseAvoidThisFallback, + enableLegacyHidden, } from 'shared/ReactFeatureFlags'; import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.old'; @@ -1499,9 +1500,8 @@ function completeWork( const prevIsHidden = prevState !== null; if ( prevIsHidden !== nextIsHidden && - newProps.mode !== 'unstable-defer-without-hiding' && // LegacyHidden doesn't do any hiding — it only pre-renders. - workInProgress.tag !== LegacyHiddenComponent + (!enableLegacyHidden || workInProgress.tag !== LegacyHiddenComponent) ) { workInProgress.flags |= Visibility; } @@ -1519,9 +1519,9 @@ function completeWork( // If so, we need to hide those nodes in the commit phase, so // schedule a visibility effect. if ( - workInProgress.tag !== LegacyHiddenComponent && - workInProgress.subtreeFlags & (Placement | Update) && - newProps.mode !== 'unstable-defer-without-hiding' + (!enableLegacyHidden || + workInProgress.tag !== LegacyHiddenComponent) && + workInProgress.subtreeFlags & (Placement | Update) ) { workInProgress.flags |= Visibility; } diff --git a/packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js b/packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js index 24e57002ef303..9b87ab65686e8 100644 --- a/packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js +++ b/packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js @@ -546,7 +546,7 @@ describe('ReactLazyContextPropagation', () => { expect(root).toMatchRenderedOutput('BB'); }); - // @gate experimental || www + // @gate www test('context is propagated through offscreen trees', async () => { const LegacyHidden = React.unstable_LegacyHidden; @@ -592,7 +592,7 @@ describe('ReactLazyContextPropagation', () => { expect(root).toMatchRenderedOutput('BB'); }); - // @gate experimental || www + // @gate www test('multiple contexts are propagated across through offscreen trees', async () => { // Same as previous test, but with multiple context providers const LegacyHidden = React.unstable_LegacyHidden; @@ -818,7 +818,7 @@ describe('ReactLazyContextPropagation', () => { expect(root).toMatchRenderedOutput('BB'); }); - // @gate experimental || www + // @gate www test('nested bailouts through offscreen trees', async () => { // Lazy context propagation will stop propagating when it hits the first // match. If we bail out again inside that tree, we must resume propagating. diff --git a/packages/react-reconciler/src/__tests__/ReactIncremental-test.js b/packages/react-reconciler/src/__tests__/ReactIncremental-test.js index 20496019984f2..8998ce6162eaa 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncremental-test.js +++ b/packages/react-reconciler/src/__tests__/ReactIncremental-test.js @@ -270,7 +270,7 @@ describe('ReactIncremental', () => { expect(inst.state).toEqual({text: 'bar', text2: 'baz'}); }); - // @gate experimental || www + // @gate www it('can deprioritize unfinished work and resume it later', () => { function Bar(props) { Scheduler.unstable_yieldValue('Bar'); @@ -316,7 +316,7 @@ describe('ReactIncremental', () => { expect(Scheduler).toFlushAndYield(['Middle', 'Middle']); }); - // @gate experimental || www + // @gate www it('can deprioritize a tree from without dropping work', () => { function Bar(props) { Scheduler.unstable_yieldValue('Bar'); @@ -1999,7 +1999,7 @@ describe('ReactIncremental', () => { }); } - // @gate experimental || www + // @gate www it('provides context when reusing work', () => { class Intl extends React.Component { static childContextTypes = { diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js index 55ce08b45450b..aafc918469c43 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js @@ -310,7 +310,7 @@ describe('ReactIncrementalErrorHandling', () => { expect(ReactNoop.getChildren()).toEqual([span('Everything is fine.')]); }); - // @gate experimental || www + // @gate www it('does not include offscreen work when retrying after an error', () => { function App(props) { if (props.isBroken) { diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js b/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js index f0c6bad86319a..e09c866d6d67d 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js @@ -424,7 +424,7 @@ describe('ReactIncrementalSideEffects', () => { ]); }); - // @gate experimental || www + // @gate www it('preserves a previously rendered node when deprioritized', () => { function Middle(props) { Scheduler.unstable_yieldValue('Middle'); @@ -475,7 +475,7 @@ describe('ReactIncrementalSideEffects', () => { ); }); - // @gate experimental || www + // @gate www it('can reuse side-effects after being preempted', () => { function Bar(props) { Scheduler.unstable_yieldValue('Bar'); @@ -555,7 +555,7 @@ describe('ReactIncrementalSideEffects', () => { ); }); - // @gate experimental || www + // @gate www it('can reuse side-effects after being preempted, if shouldComponentUpdate is false', () => { class Bar extends React.Component { shouldComponentUpdate(nextProps) { @@ -690,7 +690,7 @@ describe('ReactIncrementalSideEffects', () => { expect(ReactNoop.getChildrenAsJSX()).toEqual(); }); - // @gate experimental || www + // @gate www it('updates a child even though the old props is empty', () => { function Foo(props) { return ( @@ -930,7 +930,7 @@ describe('ReactIncrementalSideEffects', () => { expect(ops).toEqual(['Bar', 'Baz', 'Bar', 'Bar']); }); - // @gate experimental || www + // @gate www it('deprioritizes setStates that happens within a deprioritized tree', () => { const barInstances = []; diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.js index eb90d61dad6a1..3c3fddf204d5c 100644 --- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.js +++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.js @@ -667,7 +667,7 @@ describe('ReactNewContext', () => { expect(ReactNoop.getChildren()).toEqual([span(2), span(2)]); }); - // @gate experimental || www + // @gate www it("context consumer doesn't bail out inside hidden subtree", () => { const Context = React.createContext('dark'); const Consumer = getConsumer(Context); diff --git a/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js b/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js index 4dfd6459a33a3..3125fcc29e5f9 100644 --- a/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js +++ b/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js @@ -26,7 +26,7 @@ describe('ReactOffscreen', () => { return ; } - // @gate experimental || www + // @gate www it('unstable-defer-without-hiding should never toggle the visibility of its children', async () => { function App({mode}) { return ( @@ -85,7 +85,7 @@ describe('ReactOffscreen', () => { ); }); - // @gate experimental || www + // @gate www it('does not defer in legacy mode', async () => { let setState; function Foo() { @@ -130,7 +130,7 @@ describe('ReactOffscreen', () => { ); }); - // @gate experimental || www + // @gate www it('does defer in concurrent mode', async () => { let setState; function Foo() { @@ -310,7 +310,7 @@ describe('ReactOffscreen', () => { expect(root).toMatchRenderedOutput(); }); - // @gate experimental || www + // @gate www it('does not toggle effects for LegacyHidden component', async () => { // LegacyHidden is meant to be the same as offscreen except it doesn't // do anything to effects. Only used by www, as a temporary migration step. diff --git a/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.js b/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.js index fc315ae0da87b..5a135d2f06ab8 100644 --- a/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.js @@ -122,7 +122,7 @@ describe('ReactSchedulerIntegration', () => { expect(Scheduler).toHaveYielded(['A', 'B', 'C']); }); - // @gate experimental || www + // @gate www it('idle updates are not blocked by offscreen work', async () => { function Text({text}) { Scheduler.unstable_yieldValue(text); diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js index dc2d57d225a4d..3f2f4cc38aa09 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js @@ -3073,7 +3073,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(root).toMatchRenderedOutput(); }); - // @gate enableCache + // @gate enableCache && enableLegacyHidden it('should not render hidden content while suspended on higher pri', async () => { function Offscreen() { Scheduler.unstable_yieldValue('Offscreen'); @@ -3123,7 +3123,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); }); - // @gate enableCache + // @gate enableCache && enableLegacyHidden it('should be able to unblock higher pri content before suspended hidden', async () => { function Offscreen() { Scheduler.unstable_yieldValue('Offscreen'); diff --git a/packages/react-reconciler/src/getComponentNameFromFiber.js b/packages/react-reconciler/src/getComponentNameFromFiber.js index 5cb87189c975c..979914b7c4ba5 100644 --- a/packages/react-reconciler/src/getComponentNameFromFiber.js +++ b/packages/react-reconciler/src/getComponentNameFromFiber.js @@ -9,6 +9,8 @@ import type {ReactContext, ReactProviderType} from 'shared/ReactTypes'; +import {enableLegacyHidden} from 'shared/ReactFeatureFlags'; + import { FunctionComponent, ClassComponent, @@ -86,8 +88,6 @@ export default function getComponentNameFromFiber(fiber: Fiber): string | null { case LazyComponent: // Name comes from the type in this case; we don't have a tag. return getComponentNameFromType(type); - case LegacyHiddenComponent: - return 'LegacyHidden'; case Mode: if (type === REACT_STRICT_MODE_TYPE) { // Don't be less specific than shared/getComponentNameFromType @@ -120,6 +120,10 @@ export default function getComponentNameFromFiber(fiber: Fiber): string | null { return type; } break; + case LegacyHiddenComponent: + if (enableLegacyHidden) { + return 'LegacyHidden'; + } } return null; diff --git a/packages/react-refresh/src/__tests__/ReactFresh-test.js b/packages/react-refresh/src/__tests__/ReactFresh-test.js index 378f44d4ffccf..935114027783d 100644 --- a/packages/react-refresh/src/__tests__/ReactFresh-test.js +++ b/packages/react-refresh/src/__tests__/ReactFresh-test.js @@ -2411,107 +2411,106 @@ describe('ReactFresh', () => { } }); + // @gate www && __DEV__ it('can hot reload offscreen components', async () => { - if (__DEV__ && __EXPERIMENTAL__) { - const AppV1 = prepare(() => { - function Hello() { - React.useLayoutEffect(() => { - Scheduler.unstable_yieldValue('Hello#layout'); - }); - const [val, setVal] = React.useState(0); - return ( -
setVal(val + 1)}> - {val} -
- ); - } - $RefreshReg$(Hello, 'Hello'); - - return function App({offscreen}) { - React.useLayoutEffect(() => { - Scheduler.unstable_yieldValue('App#layout'); - }); - return ( -setVal(val + 1)}> + {val} +
+ ); + } + $RefreshReg$(Hello, 'Hello'); - const root = ReactDOMClient.createRoot(container); - root.render(setVal(val + 1)}> - {val} -
- ); - } - $RefreshReg$(Hello, 'Hello'); - }); + const root = ReactDOMClient.createRoot(container); + root.render(setVal(val + 1)}> + {val} +
+ ); + } + $RefreshReg$(Hello, 'Hello'); + }); - // Process the offscreen updates. - expect(Scheduler).toFlushAndYieldThrough(['Hello#layout']); - expect(container.firstChild).toBe(el); - expect(el.firstChild.textContent).toBe('0'); - expect(el.firstChild.style.color).toBe('red'); + // It's still offscreen so we don't see anything. + expect(container.firstChild).toBe(el); + expect(el.hidden).toBe(true); + expect(el.firstChild).toBe(null); - await act(async () => { - el.firstChild.dispatchEvent( - new MouseEvent('click', { - bubbles: true, - }), - ); - }); + // Process the offscreen updates. + expect(Scheduler).toFlushAndYieldThrough(['Hello#layout']); + expect(container.firstChild).toBe(el); + expect(el.firstChild.textContent).toBe('0'); + expect(el.firstChild.style.color).toBe('red'); + + await act(async () => { + el.firstChild.dispatchEvent( + new MouseEvent('click', { + bubbles: true, + }), + ); + }); - expect(Scheduler).toHaveYielded(['Hello#layout']); - expect(el.firstChild.textContent).toBe('1'); - expect(el.firstChild.style.color).toBe('red'); + expect(Scheduler).toHaveYielded(['Hello#layout']); + expect(el.firstChild.textContent).toBe('1'); + expect(el.firstChild.style.color).toBe('red'); - // Hot reload while we're offscreen. - patch(() => { - function Hello() { - React.useLayoutEffect(() => { - Scheduler.unstable_yieldValue('Hello#layout'); - }); - const [val, setVal] = React.useState(0); - return ( -setVal(val + 1)}> - {val} -
- ); - } - $RefreshReg$(Hello, 'Hello'); - }); + // Hot reload while we're offscreen. + patch(() => { + function Hello() { + React.useLayoutEffect(() => { + Scheduler.unstable_yieldValue('Hello#layout'); + }); + const [val, setVal] = React.useState(0); + return ( +setVal(val + 1)}> + {val} +
+ ); + } + $RefreshReg$(Hello, 'Hello'); + }); - // It's still offscreen so we don't see the updates. - expect(container.firstChild).toBe(el); - expect(el.firstChild.textContent).toBe('1'); - expect(el.firstChild.style.color).toBe('red'); + // It's still offscreen so we don't see the updates. + expect(container.firstChild).toBe(el); + expect(el.firstChild.textContent).toBe('1'); + expect(el.firstChild.style.color).toBe('red'); - // Process the offscreen updates. - expect(Scheduler).toFlushAndYieldThrough(['Hello#layout']); - expect(container.firstChild).toBe(el); - expect(el.firstChild.textContent).toBe('1'); - expect(el.firstChild.style.color).toBe('orange'); - } + // Process the offscreen updates. + expect(Scheduler).toFlushAndYieldThrough(['Hello#layout']); + expect(container.firstChild).toBe(el); + expect(el.firstChild.textContent).toBe('1'); + expect(el.firstChild.style.color).toBe('orange'); }); it('remounts failed error boundaries (componentDidCatch)', () => { diff --git a/packages/react/index.experimental.js b/packages/react/index.experimental.js index 19af075993d56..b54fe6fdcd0b9 100644 --- a/packages/react/index.experimental.js +++ b/packages/react/index.experimental.js @@ -32,7 +32,6 @@ export { startTransition, unstable_Cache, unstable_DebugTracingMode, - unstable_LegacyHidden, unstable_Offscreen, unstable_getCacheSignal, unstable_getCacheForType, diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 7cd1325c57890..8020d13b35154 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -101,6 +101,9 @@ export const enableTransitionTracing = false; // No known bugs, but needs performance testing export const enableLazyContextPropagation = false; +// FB-only usage. The new API has different semantics. +export const enableLegacyHidden = false; + // Enables unstable_avoidThisFallback feature in Fiber export const enableSuspenseAvoidThisFallback = false; // Enables unstable_avoidThisFallback feature in Fizz diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 8decbc01d6802..74e27292d12fe 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -70,6 +70,7 @@ export const enableUseRefAccessWarning = false; export const disableSchedulerTimeoutInWorkLoop = false; export const enableLazyContextPropagation = false; +export const enableLegacyHidden = true; export const enableSyncDefaultUpdates = true; export const allowConcurrentByDefault = true; export const enableCustomElementPropertySupport = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 3ca6029d67852..99c98f1f6560e 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -61,6 +61,7 @@ export const enableUseRefAccessWarning = false; export const disableSchedulerTimeoutInWorkLoop = false; export const enableLazyContextPropagation = false; +export const enableLegacyHidden = false; export const enableSyncDefaultUpdates = true; export const allowConcurrentByDefault = false; export const enablePersistentOffscreenHostContainer = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index ca9f71857c02f..a1fe05abc2275 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -61,6 +61,7 @@ export const enableUseRefAccessWarning = false; export const disableSchedulerTimeoutInWorkLoop = false; export const enableLazyContextPropagation = false; +export const enableLegacyHidden = false; export const enableSyncDefaultUpdates = true; export const allowConcurrentByDefault = false; export const enablePersistentOffscreenHostContainer = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js index b2afb79825479..0ee47c87fc483 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js @@ -60,6 +60,7 @@ export const enableUseRefAccessWarning = false; export const disableSchedulerTimeoutInWorkLoop = false; export const enableLazyContextPropagation = false; +export const enableLegacyHidden = false; export const enableSyncDefaultUpdates = true; export const allowConcurrentByDefault = true; export const enablePersistentOffscreenHostContainer = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 7f776d1d40f1a..b86fb3dc0a7ab 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -61,6 +61,7 @@ export const enableUseRefAccessWarning = false; export const disableSchedulerTimeoutInWorkLoop = false; export const enableLazyContextPropagation = false; +export const enableLegacyHidden = false; export const enableSyncDefaultUpdates = true; export const allowConcurrentByDefault = true; export const enablePersistentOffscreenHostContainer = false; diff --git a/packages/shared/forks/ReactFeatureFlags.testing.js b/packages/shared/forks/ReactFeatureFlags.testing.js index 30346c8c62cef..ec488337b064b 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.js @@ -61,6 +61,7 @@ export const enableUseRefAccessWarning = false; export const disableSchedulerTimeoutInWorkLoop = false; export const enableLazyContextPropagation = false; +export const enableLegacyHidden = false; export const enableSyncDefaultUpdates = true; export const allowConcurrentByDefault = false; export const enablePersistentOffscreenHostContainer = false; diff --git a/packages/shared/forks/ReactFeatureFlags.testing.www.js b/packages/shared/forks/ReactFeatureFlags.testing.www.js index e75cbaeb5a4ae..27881e5c71a2a 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.www.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.www.js @@ -61,6 +61,7 @@ export const enableUseRefAccessWarning = false; export const disableSchedulerTimeoutInWorkLoop = false; export const enableLazyContextPropagation = false; +export const enableLegacyHidden = false; export const enableSyncDefaultUpdates = true; export const allowConcurrentByDefault = true; export const enablePersistentOffscreenHostContainer = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 91a906d90bdac..251b0dbe5b7f9 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -86,6 +86,8 @@ export const enableScopeAPI = true; export const enableSuspenseCallback = true; +export const enableLegacyHidden = true; + export const enableComponentStackLocations = true; export const disableTextareaChildren = __EXPERIMENTAL__; diff --git a/packages/shared/isValidElementType.js b/packages/shared/isValidElementType.js index d3e4666e79dee..12d00f3e06f95 100644 --- a/packages/shared/isValidElementType.js +++ b/packages/shared/isValidElementType.js @@ -30,6 +30,7 @@ import { enableCache, enableTransitionTracing, enableDebugTracing, + enableLegacyHidden, } from './ReactFeatureFlags'; const REACT_MODULE_REFERENCE: Symbol = Symbol.for('react.module.reference'); @@ -47,7 +48,7 @@ export default function isValidElementType(type: mixed) { type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || - type === REACT_LEGACY_HIDDEN_TYPE || + (enableLegacyHidden && type === REACT_LEGACY_HIDDEN_TYPE) || type === REACT_OFFSCREEN_TYPE || (enableScopeAPI && type === REACT_SCOPE_TYPE) || (enableCache && type === REACT_CACHE_TYPE) ||