diff --git a/.circleci/config.yml b/.circleci/config.yml
index a978278455218..4e9d85cd8ddde 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -107,8 +107,7 @@ jobs:
- run:
command: |
mkdir -p ./build/__test_utils__
- node ./scripts/print-warnings/print-warnings.js > build/WARNINGS
- node ./scripts/print-warnings/print-warnings.js --js > build/__test_utils__/ReactAllWarnings.js
+ node ./scripts/print-warnings/print-warnings.js > build/__test_utils__/ReactAllWarnings.js
- persist_to_workspace:
root: .
paths:
diff --git a/.github/workflows/commit_artifacts.yml b/.github/workflows/commit_artifacts.yml
index 2e5007982b1cb..db72ecf2df005 100644
--- a/.github/workflows/commit_artifacts.yml
+++ b/.github/workflows/commit_artifacts.yml
@@ -119,25 +119,24 @@ jobs:
build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js
- name: Move relevant files for React in www into compiled
run: |
- mkdir -p ./compiled
- mkdir -p ./compiled/facebook-www
- mkdir -p ./compiled/babel-plugin-react-refresh
-
- # Copy the facebook-www folder into compiled
+ # Move the facebook-www folder into compiled
+ mkdir ./compiled
mv build/facebook-www ./compiled
- # Copy WARNINGS to facebook-www
- mv build/WARNINGS ./compiled/facebook-www/WARNINGS
+ # Move ReactAllWarnings.js to facebook-www
+ mkdir ./compiled/facebook-www/__test_utils__
+ mv build/__test_utils__/ReactAllWarnings.js ./compiled/facebook-www/__test_utils__/ReactAllWarnings.js
- # Copy eslint-plugin-react-hooks into facebook-www
+ # Move eslint-plugin-react-hooks into facebook-www
mv build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \
./compiled/facebook-www/eslint-plugin-react-hooks.js
- # Copy unstable_server-external-runtime.js into facebook-www
+ # Move unstable_server-external-runtime.js into facebook-www
mv build/oss-stable/react-dom/unstable_server-external-runtime.js \
./compiled/facebook-www/unstable_server-external-runtime.js
- # Copy react-refresh-babel.development.js into babel-plugin-react-refresh
+ # Move react-refresh-babel.development.js into babel-plugin-react-refresh
+ mkdir ./compiled/babel-plugin-react-refresh
mv build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js \
./compiled/babel-plugin-react-refresh/index.js
diff --git a/fixtures/dom/src/__tests__/nested-act-test.js b/fixtures/dom/src/__tests__/nested-act-test.js
index d57bef7310e41..4a4c63eaad105 100644
--- a/fixtures/dom/src/__tests__/nested-act-test.js
+++ b/fixtures/dom/src/__tests__/nested-act-test.js
@@ -20,7 +20,7 @@ describe('unmocked scheduler', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
- DOMAct = require('react-dom/test-utils').act;
+ DOMAct = React.unstable_act;
TestRenderer = require('react-test-renderer');
TestAct = TestRenderer.act;
});
@@ -61,7 +61,7 @@ describe('mocked scheduler', () => {
require.requireActual('scheduler/unstable_mock')
);
React = require('react');
- DOMAct = require('react-dom/test-utils').act;
+ DOMAct = React.unstable_act;
TestRenderer = require('react-test-renderer');
TestAct = TestRenderer.act;
});
diff --git a/packages/react-cache/src/__tests__/ReactCacheOld-test.internal.js b/packages/react-cache/src/__tests__/ReactCacheOld-test.internal.js
index 9463b72e14a69..2403d2de286b1 100644
--- a/packages/react-cache/src/__tests__/ReactCacheOld-test.internal.js
+++ b/packages/react-cache/src/__tests__/ReactCacheOld-test.internal.js
@@ -121,7 +121,7 @@ describe('ReactCache', () => {
}
ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Suspend! [Hi]', 'Loading...']);
@@ -141,7 +141,7 @@ describe('ReactCache', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Suspend! [Hi]', 'Loading...']);
@@ -181,7 +181,7 @@ describe('ReactCache', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -210,7 +210,7 @@ describe('ReactCache', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
await waitForAll(['Suspend! [1]', 'Loading...']);
@@ -298,7 +298,7 @@ describe('ReactCache', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -356,7 +356,7 @@ describe('ReactCache', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -372,7 +372,7 @@ describe('ReactCache', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
diff --git a/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js
index 5da6b8de2a42e..eabcbd215bfb2 100644
--- a/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js
+++ b/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js
@@ -254,7 +254,7 @@ describe('React hooks DevTools integration', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
),
);
diff --git a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js
index 891e4f3e73834..cba7b3b2e7b61 100644
--- a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js
+++ b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js
@@ -75,7 +75,7 @@ describe('InspectedElement', () => {
// Used by inspectElementAtIndex() helper function
utils.act(() => {
testRendererInstance = TestRenderer.create(null, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
@@ -307,7 +307,7 @@ describe('InspectedElement', () => {
['An update to %s inside a test was not wrapped in act'],
() => {
testRendererInstance = TestRenderer.create(null, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
},
);
@@ -469,7 +469,7 @@ describe('InspectedElement', () => {
['An update to %s inside a test was not wrapped in act'],
() => {
testRendererInstance = TestRenderer.create(null, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
},
);
@@ -2034,7 +2034,7 @@ describe('InspectedElement', () => {
['An update to %s inside a test was not wrapped in act'],
() => {
testRendererInstance = TestRenderer.create(null, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
},
);
@@ -2317,7 +2317,7 @@ describe('InspectedElement', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
}, false);
await utils.actAsync(() => {
@@ -2817,7 +2817,7 @@ describe('InspectedElement', () => {
['An update to %s inside a test was not wrapped in act'],
() => {
testRendererInstance = TestRenderer.create(null, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
},
);
diff --git a/packages/react-devtools-shared/src/__tests__/utils.js b/packages/react-devtools-shared/src/__tests__/utils.js
index 0c5a0b09f7d01..bf5a8b98eab23 100644
--- a/packages/react-devtools-shared/src/__tests__/utils.js
+++ b/packages/react-devtools-shared/src/__tests__/utils.js
@@ -19,7 +19,7 @@ export function act(
recursivelyFlush: boolean = true,
): void {
const {act: actTestRenderer} = require('react-test-renderer');
- const {act: actDOM} = require('react-dom/test-utils');
+ const actDOM = require('react').unstable_act;
actDOM(() => {
actTestRenderer(() => {
@@ -44,7 +44,7 @@ export async function actAsync(
recursivelyFlush: boolean = true,
): Promise {
const {act: actTestRenderer} = require('react-test-renderer');
- const {act: actDOM} = require('react-dom/test-utils');
+ const actDOM = require('react').unstable_act;
await actDOM(async () => {
await actTestRenderer(async () => {
diff --git a/packages/react-dom/src/__tests__/ReactDOMHydrationDiff-test.js b/packages/react-dom/src/__tests__/ReactDOMHydrationDiff-test.js
index 3bdcd9c16a966..45de6fa9104f4 100644
--- a/packages/react-dom/src/__tests__/ReactDOMHydrationDiff-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMHydrationDiff-test.js
@@ -25,7 +25,7 @@ describe('ReactDOMServerHydration', () => {
React = require('react');
ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
- act = require('react-dom/test-utils').act;
+ act = React.unstable_act;
console.error = jest.fn();
container = document.createElement('div');
diff --git a/packages/react-dom/src/__tests__/ReactDOMInput-test.js b/packages/react-dom/src/__tests__/ReactDOMInput-test.js
index be4b59ce0806e..6b8baaddbe023 100644
--- a/packages/react-dom/src/__tests__/ReactDOMInput-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMInput-test.js
@@ -110,7 +110,10 @@ describe('ReactDOMInput', () => {
expect(() => {
ReactDOM.render(, container);
}).toErrorDev(
- 'Warning: You provided a `value` prop to a form field without an `onChange` handler.',
+ 'Warning: You provided a `value` prop to a form ' +
+ 'field without an `onChange` handler. This will render a read-only ' +
+ 'field. If the field should be mutable use `defaultValue`. ' +
+ 'Otherwise, set either `onChange` or `readOnly`.',
);
});
@@ -118,7 +121,10 @@ describe('ReactDOMInput', () => {
expect(() => {
ReactDOM.render(, container);
}).toErrorDev(
- 'Warning: You provided a `value` prop to a form field without an `onChange` handler.',
+ 'Warning: You provided a `value` prop to a form ' +
+ 'field without an `onChange` handler. This will render a read-only ' +
+ 'field. If the field should be mutable use `defaultValue`. ' +
+ 'Otherwise, set either `onChange` or `readOnly`.',
);
});
@@ -126,7 +132,10 @@ describe('ReactDOMInput', () => {
expect(() => {
ReactDOM.render(, container);
}).toErrorDev(
- 'Warning: You provided a `value` prop to a form field without an `onChange` handler.',
+ 'Warning: You provided a `value` prop to a form ' +
+ 'field without an `onChange` handler. This will render a read-only ' +
+ 'field. If the field should be mutable use `defaultValue`. ' +
+ 'Otherwise, set either `onChange` or `readOnly`.',
);
});
diff --git a/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js b/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js
index 39a1bac1e9ede..810452c64a313 100644
--- a/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js
@@ -759,4 +759,85 @@ describe('ReactDOMTextarea', () => {
ReactDOM.render(, container);
expect(node.defaultValue).toBe('');
});
+
+ it('should not warn about missing onChange if value is not set', () => {
+ expect(() => {
+ ReactTestUtils.renderIntoDocument();
+ }).not.toThrow();
+ });
+
+ it('should not warn about missing onChange if value is undefined', () => {
+ expect(() => {
+ ReactTestUtils.renderIntoDocument();
+ }).not.toThrow();
+ });
+
+ it('should not warn about missing onChange if onChange is set', () => {
+ expect(() => {
+ const change = jest.fn();
+ ReactTestUtils.renderIntoDocument(
+ ,
+ );
+ }).not.toThrow();
+ });
+
+ it('should not warn about missing onChange if disabled is true', () => {
+ expect(() => {
+ ReactTestUtils.renderIntoDocument(
+ ,
+ );
+ }).not.toThrow();
+ });
+
+ it('should not warn about missing onChange if value is not set', () => {
+ expect(() => {
+ ReactTestUtils.renderIntoDocument(
+ ,
+ );
+ }).not.toThrow();
+ });
+
+ it('should warn about missing onChange if value is false', () => {
+ expect(() =>
+ ReactTestUtils.renderIntoDocument(),
+ ).toErrorDev(
+ 'Warning: You provided a `value` prop to a form ' +
+ 'field without an `onChange` handler. This will render a read-only ' +
+ 'field. If the field should be mutable use `defaultValue`. ' +
+ 'Otherwise, set either `onChange` or `readOnly`.',
+ );
+ });
+
+ it('should warn about missing onChange if value is 0', () => {
+ expect(() =>
+ ReactTestUtils.renderIntoDocument(),
+ ).toErrorDev(
+ 'Warning: You provided a `value` prop to a form ' +
+ 'field without an `onChange` handler. This will render a read-only ' +
+ 'field. If the field should be mutable use `defaultValue`. ' +
+ 'Otherwise, set either `onChange` or `readOnly`.',
+ );
+ });
+
+ it('should warn about missing onChange if value is "0"', () => {
+ expect(() =>
+ ReactTestUtils.renderIntoDocument(),
+ ).toErrorDev(
+ 'Warning: You provided a `value` prop to a form ' +
+ 'field without an `onChange` handler. This will render a read-only ' +
+ 'field. If the field should be mutable use `defaultValue`. ' +
+ 'Otherwise, set either `onChange` or `readOnly`.',
+ );
+ });
+
+ it('should warn about missing onChange if value is ""', () => {
+ expect(() =>
+ ReactTestUtils.renderIntoDocument(),
+ ).toErrorDev(
+ 'Warning: You provided a `value` prop to a form ' +
+ 'field without an `onChange` handler. This will render a read-only ' +
+ 'field. If the field should be mutable use `defaultValue`. ' +
+ 'Otherwise, set either `onChange` or `readOnly`.',
+ );
+ });
});
diff --git a/packages/react-dom/src/__tests__/ReactTestUtilsActUnmockedScheduler-test.js b/packages/react-dom/src/__tests__/ReactTestUtilsActUnmockedScheduler-test.js
index e0bce1c01ca69..a38d4c0698ced 100644
--- a/packages/react-dom/src/__tests__/ReactTestUtilsActUnmockedScheduler-test.js
+++ b/packages/react-dom/src/__tests__/ReactTestUtilsActUnmockedScheduler-test.js
@@ -37,7 +37,7 @@ beforeEach(() => {
yields = [];
React = require('react');
ReactDOM = require('react-dom');
- act = require('react-dom/test-utils').act;
+ act = React.unstable_act;
container = document.createElement('div');
document.body.appendChild(container);
});
diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js
index 905eda36a93e8..7e056f2e71068 100644
--- a/packages/react-reconciler/src/ReactFiberLane.js
+++ b/packages/react-reconciler/src/ReactFiberLane.js
@@ -25,6 +25,9 @@ import {
enableTransitionTracing,
enableUnifiedSyncLane,
enableUpdaterTracking,
+ syncLaneExpirationMs,
+ transitionLaneExpirationMs,
+ retryLaneExpirationMs,
} from 'shared/ReactFeatureFlags';
import {isDevToolsPresent} from './ReactFiberDevToolsHook';
import {ConcurrentUpdatesByDefaultMode, NoMode} from './ReactTypeOfMode';
@@ -355,7 +358,7 @@ function computeExpirationTime(lane: Lane, currentTime: number) {
// to fix the starvation. However, this scenario supports the idea that
// expiration times are an important safeguard when starvation
// does happen.
- return currentTime + 250;
+ return currentTime + syncLaneExpirationMs;
case DefaultHydrationLane:
case DefaultLane:
case TransitionHydrationLane:
@@ -374,7 +377,7 @@ function computeExpirationTime(lane: Lane, currentTime: number) {
case TransitionLane13:
case TransitionLane14:
case TransitionLane15:
- return currentTime + 5000;
+ return currentTime + transitionLaneExpirationMs;
case RetryLane1:
case RetryLane2:
case RetryLane3:
@@ -384,7 +387,9 @@ function computeExpirationTime(lane: Lane, currentTime: number) {
// crashes. There must be some other underlying bug; not super urgent but
// ideally should figure out why and fix it. Unfortunately we don't have
// a repro for the crashes, only detected via production metrics.
- return enableRetryLaneExpiration ? currentTime + 5000 : NoTimestamp;
+ return enableRetryLaneExpiration
+ ? currentTime + retryLaneExpirationMs
+ : NoTimestamp;
case SelectiveHydrationLane:
case IdleHydrationLane:
case IdleLane:
@@ -423,7 +428,9 @@ export function markStarvedLanesAsExpired(
// We exclude retry lanes because those must always be time sliced, in order
// to unwrap uncached promises.
// TODO: Write a test for this
- let lanes = pendingLanes & ~RetryLanes;
+ let lanes = enableRetryLaneExpiration
+ ? pendingLanes
+ : pendingLanes & ~RetryLanes;
while (lanes > 0) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
diff --git a/packages/react-reconciler/src/__tests__/DebugTracing-test.internal.js b/packages/react-reconciler/src/__tests__/DebugTracing-test.internal.js
index f8026d6ea9fab..041086690e7fe 100644
--- a/packages/react-reconciler/src/__tests__/DebugTracing-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/DebugTracing-test.internal.js
@@ -67,7 +67,7 @@ describe('DebugTracing', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
),
);
expect(logs).toEqual([]);
@@ -179,7 +179,7 @@ describe('DebugTracing', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
),
);
@@ -216,7 +216,7 @@ describe('DebugTracing', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
),
);
@@ -247,7 +247,7 @@ describe('DebugTracing', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
),
);
@@ -278,7 +278,7 @@ describe('DebugTracing', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
),
);
}).toErrorDev('Cannot update during an existing state transition');
@@ -305,7 +305,7 @@ describe('DebugTracing', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
),
);
@@ -333,7 +333,7 @@ describe('DebugTracing', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
expect(logs).toEqual([
@@ -358,7 +358,7 @@ describe('DebugTracing', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
@@ -381,7 +381,7 @@ describe('DebugTracing', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
),
);
diff --git a/packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js b/packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js
index 71e047afc5ff6..0ce51699849b7 100644
--- a/packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ErrorBoundaryReconciliation-test.internal.js
@@ -59,7 +59,7 @@ describe('ErrorBoundaryReconciliation', () => {
,
- {unstable_isConcurrent: isConcurrent},
+ {isConcurrent: isConcurrent},
);
});
expect(renderer).toMatchRenderedOutput();
diff --git a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
index 5f09cf997907c..5da503c8ca34d 100644
--- a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
@@ -86,7 +86,7 @@ describe('ReactHooks', () => {
return ;
}
- const root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
+ const root = ReactTestRenderer.create(null, {isConcurrent: true});
root.update();
await waitForAll(['Parent: 0, 0', 'Child: 0, 0', 'Effect: 0, 0']);
expect(root).toMatchRenderedOutput('0, 0');
@@ -174,7 +174,7 @@ describe('ReactHooks', () => {
Parent = memo(Parent);
- const root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
+ const root = ReactTestRenderer.create(null, {isConcurrent: true});
root.update();
await waitForAll(['Parent: 0, 0 (light)', 'Child: 0, 0 (light)']);
expect(root).toMatchRenderedOutput('0, 0 (light)');
@@ -232,7 +232,7 @@ describe('ReactHooks', () => {
return counter;
}
- const root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
+ const root = ReactTestRenderer.create(null, {isConcurrent: true});
root.update();
await waitForAll(['Count: 0']);
expect(root).toMatchRenderedOutput('0');
@@ -266,7 +266,7 @@ describe('ReactHooks', () => {
return counter;
}
- const root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
+ const root = ReactTestRenderer.create(null, {isConcurrent: true});
root.update();
await waitForAll(['Count: 0']);
expect(root).toMatchRenderedOutput('0');
@@ -322,7 +322,7 @@ describe('ReactHooks', () => {
});
return ;
}
- const root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
+ const root = ReactTestRenderer.create(null, {isConcurrent: true});
await act(() => {
root.update(
@@ -390,7 +390,7 @@ describe('ReactHooks', () => {
return ;
}
- const root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
+ const root = ReactTestRenderer.create(null, {isConcurrent: true});
root.update();
await waitForAll(['Parent: 0', 'Child: 0', 'Effect: 0']);
expect(root).toMatchRenderedOutput('0');
@@ -465,7 +465,7 @@ describe('ReactHooks', () => {
return ;
}
- const root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
+ const root = ReactTestRenderer.create(null, {isConcurrent: true});
root.update();
await waitForAll(['Parent: 0', 'Child: 0']);
expect(root).toMatchRenderedOutput('0');
@@ -523,7 +523,7 @@ describe('ReactHooks', () => {
return ;
}
- const root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
+ const root = ReactTestRenderer.create(null, {isConcurrent: true});
root.update();
await waitForAll(['Parent: 1', 'Child: 1']);
expect(root).toMatchRenderedOutput('1');
diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
index a96c60bc26e88..36e956256dc60 100644
--- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
@@ -99,7 +99,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -185,7 +185,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -208,7 +208,7 @@ describe('ReactLazy', () => {
const LazyText = lazy(async () => Text);
const root = ReactTestRenderer.create(null, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
let error;
@@ -242,7 +242,7 @@ describe('ReactLazy', () => {
});
const root = ReactTestRenderer.create(null, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
let error;
@@ -302,7 +302,7 @@ describe('ReactLazy', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Suspend! [LazyChildA]', 'Loading...']);
@@ -337,7 +337,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -394,7 +394,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
await waitForAll(['Loading...']);
@@ -440,7 +440,7 @@ describe('ReactLazy', () => {
>,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
await waitForAll(['Not lazy: 0', 'Loading...']);
@@ -485,7 +485,7 @@ describe('ReactLazy', () => {
>,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
await waitForAll(['Not lazy: 0', 'Loading...']);
@@ -561,7 +561,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -691,7 +691,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -734,7 +734,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -761,7 +761,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -815,7 +815,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -1012,7 +1012,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -1055,7 +1055,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -1100,7 +1100,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -1131,7 +1131,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
await waitForAll(['Loading...']);
@@ -1218,7 +1218,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
await waitForAll(['Loading...']);
@@ -1264,7 +1264,7 @@ describe('ReactLazy', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -1304,7 +1304,7 @@ describe('ReactLazy', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
await waitForAll(['Loading...']);
@@ -1412,7 +1412,7 @@ describe('ReactLazy', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Init A', 'Loading...']);
@@ -1497,7 +1497,7 @@ describe('ReactLazy', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: false,
+ isConcurrent: false,
});
assertLog(['Init A', 'Init B', 'Loading...']);
@@ -1559,7 +1559,7 @@ describe('ReactLazy', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Init A', 'Loading...']);
@@ -1628,7 +1628,7 @@ describe('ReactLazy', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: false,
+ isConcurrent: false,
});
assertLog(['Init A', 'Loading...']);
diff --git a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js
index 6e347b900f655..4440f900294a7 100644
--- a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js
@@ -117,7 +117,7 @@ describe('ReactSuspense', () => {
// Render an empty shell
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Foo']);
@@ -158,7 +158,7 @@ describe('ReactSuspense', () => {
>,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
@@ -217,7 +217,7 @@ describe('ReactSuspense', () => {
>,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
await waitForAll(['Initial']);
@@ -268,7 +268,7 @@ describe('ReactSuspense', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Foo', 'Suspend! [A]', 'Loading...']);
@@ -303,7 +303,7 @@ describe('ReactSuspense', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Foo', 'Suspend! [A]', 'Loading...']);
@@ -353,7 +353,7 @@ describe('ReactSuspense', () => {
}
const root = ReactTestRenderer.create(null, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
root.update();
@@ -456,7 +456,7 @@ describe('ReactSuspense', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Suspend! [default]', 'Loading...']);
@@ -502,7 +502,7 @@ describe('ReactSuspense', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Suspend! [default]', 'Loading...']);
@@ -545,7 +545,7 @@ describe('ReactSuspense', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
await waitForAll(['Suspend! [default]', 'Loading...']);
@@ -589,7 +589,7 @@ describe('ReactSuspense', () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
await waitForAll(['Suspend! [default]', 'Loading...']);
@@ -631,7 +631,7 @@ describe('ReactSuspense', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Child 1', 'create layout']);
@@ -899,7 +899,7 @@ describe('ReactSuspense', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
// Initial render
@@ -990,7 +990,7 @@ describe('ReactSuspense', () => {
}
const root = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['Suspend! [Child 1]', 'Loading...']);
diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js
index d93c8bcf606ab..77aae6ee53d9b 100644
--- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js
@@ -5,6 +5,7 @@ let Scheduler;
let act;
let waitFor;
let waitForAll;
+let waitForMicrotasks;
let assertLog;
let waitForPaint;
let Suspense;
@@ -29,6 +30,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
waitFor = InternalTestUtils.waitFor;
waitForAll = InternalTestUtils.waitForAll;
waitForPaint = InternalTestUtils.waitForPaint;
+ waitForMicrotasks = InternalTestUtils.waitForMicrotasks;
assertLog = InternalTestUtils.assertLog;
getCacheForType = React.unstable_getCacheForType;
@@ -4008,4 +4010,74 @@ describe('ReactSuspenseWithNoopRenderer', () => {
);
},
);
+
+ // @gate enableLegacyCache && enableRetryLaneExpiration
+ it('recurring updates in siblings should not block expensive content in suspense boundary from committing', async () => {
+ const {useState} = React;
+
+ let setText;
+ function UpdatingText() {
+ const [text, _setText] = useState('1');
+ setText = _setText;
+ return ;
+ }
+
+ function ExpensiveText({text, ms}) {
+ Scheduler.log(text);
+ Scheduler.unstable_advanceTime(ms);
+ return ;
+ }
+
+ function App() {
+ return (
+ <>
+
+ }>
+
+
+
+
+
+ >
+ );
+ }
+
+ const root = ReactNoop.createRoot();
+ root.render();
+ await waitForAll(['1', 'Suspend! [Async]', 'Loading...']);
+ expect(root).toMatchRenderedOutput(
+ <>
+
+
+ >,
+ );
+
+ await resolveText('Async');
+ expect(root).toMatchRenderedOutput(
+ <>
+
+
+ >,
+ );
+
+ await waitFor(['Async', 'A', 'B']);
+ ReactNoop.expire(100000);
+ await advanceTimers(100000);
+ setText('2');
+ await waitForPaint(['2']);
+
+ await waitForMicrotasks();
+ Scheduler.unstable_flushNumberOfYields(1);
+ assertLog(['Async', 'A', 'B', 'C']);
+
+ expect(root).toMatchRenderedOutput(
+ <>
+
+
+
+
+
+ >,
+ );
+ });
});
diff --git a/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js b/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js
index f7c30616c98c1..af35defe2325c 100644
--- a/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js
+++ b/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js
@@ -76,7 +76,7 @@ describe('StrictEffectsMode', () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
@@ -129,7 +129,7 @@ describe('StrictEffectsMode', () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
@@ -182,7 +182,7 @@ describe('StrictEffectsMode', () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
@@ -233,7 +233,7 @@ describe('StrictEffectsMode', () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
@@ -286,7 +286,7 @@ describe('StrictEffectsMode', () => {
}
await act(() => {
- ReactTestRenderer.create(, {unstable_isConcurrent: true});
+ ReactTestRenderer.create(, {isConcurrent: true});
});
if (supportsDoubleInvokeEffects()) {
@@ -322,7 +322,7 @@ describe('StrictEffectsMode', () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
@@ -367,7 +367,7 @@ describe('StrictEffectsMode', () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
@@ -438,7 +438,7 @@ describe('StrictEffectsMode', () => {
await act(() => {
ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
@@ -502,7 +502,7 @@ describe('StrictEffectsMode', () => {
}
await act(() => {
- ReactTestRenderer.create(, {unstable_isConcurrent: true});
+ ReactTestRenderer.create(, {isConcurrent: true});
});
if (supportsDoubleInvokeEffects()) {
@@ -586,7 +586,7 @@ describe('StrictEffectsMode', () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
@@ -667,7 +667,7 @@ describe('StrictEffectsMode', () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
diff --git a/packages/react-refresh/src/__tests__/ReactFresh-test.js b/packages/react-refresh/src/__tests__/ReactFresh-test.js
index aa7b2504227e0..8ce009ed72043 100644
--- a/packages/react-refresh/src/__tests__/ReactFresh-test.js
+++ b/packages/react-refresh/src/__tests__/ReactFresh-test.js
@@ -34,7 +34,7 @@ describe('ReactFresh', () => {
ReactDOM = require('react-dom');
ReactDOMClient = require('react-dom/client');
Scheduler = require('scheduler');
- act = require('react-dom/test-utils').act;
+ act = React.unstable_act;
internalAct = require('internal-test-utils').act;
const InternalTestUtils = require('internal-test-utils');
@@ -3792,7 +3792,7 @@ describe('ReactFresh', () => {
React = require('react');
ReactDOM = require('react-dom');
Scheduler = require('scheduler');
- act = require('react-dom/test-utils').act;
+ act = React.unstable_act;
internalAct = require('internal-test-utils').act;
// Important! Inject into the global hook *after* ReactDOM runs:
diff --git a/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js b/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js
index 54e596f6232c3..ee7a9230bb14e 100644
--- a/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js
+++ b/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js
@@ -31,7 +31,7 @@ describe('ReactFreshIntegration', () => {
ReactFreshRuntime = require('react-refresh/runtime');
ReactFreshRuntime.injectIntoGlobalHook(global);
ReactDOM = require('react-dom');
- act = require('react-dom/test-utils').act;
+ act = React.unstable_act;
container = document.createElement('div');
document.body.appendChild(container);
exportsObj = undefined;
diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js
index eebca4710e954..c12c6904b872f 100644
--- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js
+++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js
@@ -32,6 +32,7 @@ let ReactDOMClient;
let ReactServerDOMServer;
let ReactServerDOMClient;
let ReactDOMFizzServer;
+let ReactDOMStaticServer;
let Suspense;
let ErrorBoundary;
let JSDOM;
@@ -71,6 +72,7 @@ describe('ReactFlightDOM', () => {
Suspense = React.Suspense;
ReactDOMClient = require('react-dom/client');
ReactDOMFizzServer = require('react-dom/server.node');
+ ReactDOMStaticServer = require('react-dom/static.node');
ReactServerDOMClient = require('react-server-dom-webpack/client');
ErrorBoundary = class extends React.Component {
@@ -1300,6 +1302,91 @@ describe('ReactFlightDOM', () => {
expect(getMeaningfulChildren(container)).toEqual(hello world
);
});
+ // @gate enablePostpone
+ it('should allow postponing in Flight through a serialized promise', async () => {
+ const Context = React.createContext();
+ const ContextProvider = Context.Provider;
+
+ function Foo() {
+ const value = React.use(React.useContext(Context));
+ return {value};
+ }
+
+ const ClientModule = clientExports({
+ ContextProvider,
+ Foo,
+ });
+
+ async function getFoo() {
+ React.unstable_postpone('foo');
+ }
+
+ function App() {
+ return (
+
+
+
+
+
+
+
+ );
+ }
+
+ const {writable, readable} = getTestStream();
+
+ const {pipe} = ReactServerDOMServer.renderToPipeableStream(
+ ,
+ webpackMap,
+ );
+ pipe(writable);
+
+ let response = null;
+ function getResponse() {
+ if (response === null) {
+ response = ReactServerDOMClient.createFromReadableStream(readable);
+ }
+ return response;
+ }
+
+ function Response() {
+ return getResponse();
+ }
+
+ const errors = [];
+ function onError(error, errorInfo) {
+ errors.push(error, errorInfo);
+ }
+ const result = await ReactDOMStaticServer.prerenderToNodeStream(
+ ,
+ {
+ onError,
+ },
+ );
+
+ const prelude = await new Promise((resolve, reject) => {
+ let content = '';
+ result.prelude.on('data', chunk => {
+ content += Buffer.from(chunk).toString('utf8');
+ });
+ result.prelude.on('error', error => {
+ reject(error);
+ });
+ result.prelude.on('end', () => resolve(content));
+ });
+
+ expect(errors).toEqual([]);
+ const doc = new JSDOM(prelude).window.document;
+ expect(getMeaningfulChildren(doc)).toEqual(
+
+
+
+ loading...
+
+ ,
+ );
+ });
+
it('should support float methods when rendering in Fizz', async () => {
function Component() {
return hello world
;
diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMForm-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMForm-test.js
index d21c456b8e087..89b436907f201 100644
--- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMForm-test.js
+++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMForm-test.js
@@ -54,7 +54,7 @@ describe('ReactFlightDOMForm', () => {
ReactServerDOMClient = require('react-server-dom-webpack/client.edge');
ReactDOMServer = require('react-dom/server.edge');
ReactDOMClient = require('react-dom/client');
- act = require('react-dom/test-utils').act;
+ act = React.unstable_act;
useFormState = require('react-dom').useFormState;
container = document.createElement('div');
document.body.appendChild(container);
diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js
index 479a4a746d5e2..cc65f746f42e8 100644
--- a/packages/react-server/src/ReactFlightServer.js
+++ b/packages/react-server/src/ReactFlightServer.js
@@ -407,11 +407,21 @@ function serializeThenable(request: Request, thenable: Thenable): number {
pingTask(request, newTask);
},
reason => {
- newTask.status = ERRORED;
+ if (
+ enablePostpone &&
+ typeof reason === 'object' &&
+ reason !== null &&
+ (reason: any).$$typeof === REACT_POSTPONE_TYPE
+ ) {
+ const postponeInstance: Postpone = (reason: any);
+ logPostpone(request, postponeInstance.message);
+ emitPostponeChunk(request, newTask.id, postponeInstance);
+ } else {
+ newTask.status = ERRORED;
+ const digest = logRecoverableError(request, reason);
+ emitErrorChunk(request, newTask.id, digest, reason);
+ }
request.abortableTasks.delete(newTask);
- // TODO: We should ideally do this inside performWork so it's scheduled
- const digest = logRecoverableError(request, reason);
- emitErrorChunk(request, newTask.id, digest, reason);
if (request.destination !== null) {
flushCompletedChunks(request, request.destination);
}
diff --git a/packages/react-test-renderer/src/ReactTestRenderer.js b/packages/react-test-renderer/src/ReactTestRenderer.js
index 273bcd128f47c..4b19f599db5ac 100644
--- a/packages/react-test-renderer/src/ReactTestRenderer.js
+++ b/packages/react-test-renderer/src/ReactTestRenderer.js
@@ -60,6 +60,7 @@ const act = React.unstable_act;
type TestRendererOptions = {
createNodeMock: (element: React$Element) => any,
+ isConcurrent: boolean,
unstable_isConcurrent: boolean,
unstable_strictMode: boolean,
unstable_concurrentUpdatesByDefault: boolean,
@@ -479,7 +480,10 @@ function create(
// $FlowFixMe[incompatible-type] found when upgrading Flow
createNodeMock = options.createNodeMock;
}
- if (options.unstable_isConcurrent === true) {
+ if (
+ options.unstable_isConcurrent === true ||
+ options.isConcurrent === true
+ ) {
isConcurrent = true;
}
if (options.unstable_strictMode === true) {
diff --git a/packages/react-test-renderer/src/__tests__/ReactTestRendererAsync-test.js b/packages/react-test-renderer/src/__tests__/ReactTestRendererAsync-test.js
index 468f62d39a722..51c7e0a950ddc 100644
--- a/packages/react-test-renderer/src/__tests__/ReactTestRendererAsync-test.js
+++ b/packages/react-test-renderer/src/__tests__/ReactTestRendererAsync-test.js
@@ -34,7 +34,7 @@ describe('ReactTestRendererAsync', () => {
return props.children;
}
const renderer = ReactTestRenderer.create(Hi, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
// Before flushing, nothing has mounted.
@@ -68,7 +68,7 @@ describe('ReactTestRendererAsync', () => {
);
}
const renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
await waitForAll(['A:1', 'B:1', 'C:1']);
@@ -97,7 +97,7 @@ describe('ReactTestRendererAsync', () => {
let renderer;
React.startTransition(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
@@ -137,7 +137,7 @@ describe('ReactTestRendererAsync', () => {
let renderer;
React.startTransition(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js
index 25386df33abcf..fd42561393101 100644
--- a/packages/react/src/__tests__/ReactProfiler-test.internal.js
+++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js
@@ -213,7 +213,7 @@ describe(`onRender`, () => {
,
{
- unstable_isConcurrent: true,
+ isConcurrent: true,
},
);
});
@@ -752,7 +752,7 @@ describe(`onRender`, () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
@@ -793,7 +793,7 @@ describe(`onRender`, () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
@@ -844,7 +844,7 @@ describe(`onRender`, () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
@@ -897,7 +897,7 @@ describe(`onRender`, () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
// Render everything initially.
@@ -1002,7 +1002,7 @@ describe(`onRender`, () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
// Render everything initially.
diff --git a/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js b/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js
index d28e2ad8de64a..572abd354da63 100644
--- a/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js
+++ b/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js
@@ -150,7 +150,7 @@ describe('ReactProfiler DevTools integration', () => {
return text;
}
- const root = ReactTestRenderer.create(null, {unstable_isConcurrent: true});
+ const root = ReactTestRenderer.create(null, {isConcurrent: true});
// Commit something
root.update();
diff --git a/packages/react/src/__tests__/ReactStartTransition-test.js b/packages/react/src/__tests__/ReactStartTransition-test.js
index 9e689ac6e7105..c98372a7c74b7 100644
--- a/packages/react/src/__tests__/ReactStartTransition-test.js
+++ b/packages/react/src/__tests__/ReactStartTransition-test.js
@@ -49,7 +49,7 @@ describe('ReactStartTransition', () => {
await act(() => {
ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
diff --git a/packages/scheduler/src/SchedulerFeatureFlags.js b/packages/scheduler/src/SchedulerFeatureFlags.js
index 182093a93c85c..5d207922ca968 100644
--- a/packages/scheduler/src/SchedulerFeatureFlags.js
+++ b/packages/scheduler/src/SchedulerFeatureFlags.js
@@ -14,3 +14,7 @@ export const enableIsInputPendingContinuous = false;
export const frameYieldMs = 5;
export const continuousYieldMs = 50;
export const maxYieldMs = 300;
+
+export const userBlockingPriorityTimeout = 250;
+export const normalPriorityTimeout = 5000;
+export const lowPriorityTimeout = 10000;
diff --git a/packages/scheduler/src/forks/Scheduler.js b/packages/scheduler/src/forks/Scheduler.js
index 2263b706aad35..e4eb17b37a2c9 100644
--- a/packages/scheduler/src/forks/Scheduler.js
+++ b/packages/scheduler/src/forks/Scheduler.js
@@ -19,6 +19,9 @@ import {
frameYieldMs,
continuousYieldMs,
maxYieldMs,
+ userBlockingPriorityTimeout,
+ lowPriorityTimeout,
+ normalPriorityTimeout,
} from '../SchedulerFeatureFlags';
import {push, pop, peek} from '../SchedulerMinHeap';
@@ -75,15 +78,6 @@ if (hasPerformanceNow) {
// 0b111111111111111111111111111111
var maxSigned31BitInt = 1073741823;
-// Times out immediately
-var IMMEDIATE_PRIORITY_TIMEOUT = -1;
-// Eventually times out
-var USER_BLOCKING_PRIORITY_TIMEOUT = 250;
-var NORMAL_PRIORITY_TIMEOUT = 5000;
-var LOW_PRIORITY_TIMEOUT = 10000;
-// Never times out
-var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt;
-
// Tasks are stored on a min heap
var taskQueue: Array = [];
var timerQueue: Array = [];
@@ -362,20 +356,25 @@ function unstable_scheduleCallback(
var timeout;
switch (priorityLevel) {
case ImmediatePriority:
- timeout = IMMEDIATE_PRIORITY_TIMEOUT;
+ // Times out immediately
+ timeout = -1;
break;
case UserBlockingPriority:
- timeout = USER_BLOCKING_PRIORITY_TIMEOUT;
+ // Eventually times out
+ timeout = userBlockingPriorityTimeout;
break;
case IdlePriority:
- timeout = IDLE_PRIORITY_TIMEOUT;
+ // Never times out
+ timeout = maxSigned31BitInt;
break;
case LowPriority:
- timeout = LOW_PRIORITY_TIMEOUT;
+ // Eventually times out
+ timeout = lowPriorityTimeout;
break;
case NormalPriority:
default:
- timeout = NORMAL_PRIORITY_TIMEOUT;
+ // Eventually times out
+ timeout = normalPriorityTimeout;
break;
}
diff --git a/packages/scheduler/src/forks/SchedulerFeatureFlags.www-dynamic.js b/packages/scheduler/src/forks/SchedulerFeatureFlags.www-dynamic.js
index 8232400b84d32..25d88aa4b903d 100644
--- a/packages/scheduler/src/forks/SchedulerFeatureFlags.www-dynamic.js
+++ b/packages/scheduler/src/forks/SchedulerFeatureFlags.www-dynamic.js
@@ -12,3 +12,7 @@
// with the __VARIANT__ set to `true`, and once set to `false`.
export const enableProfiling = __VARIANT__;
+
+export const userBlockingPriorityTimeout = 250;
+export const normalPriorityTimeout = 5000;
+export const lowPriorityTimeout = 10000;
diff --git a/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js b/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js
index 4ad93cb70e594..a0713261db996 100644
--- a/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js
+++ b/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js
@@ -7,10 +7,16 @@
* @flow
*/
-const {enableProfiling: enableProfilingFeatureFlag} =
- // $FlowFixMe[cannot-resolve-module]
- require('SchedulerFeatureFlags');
+// $FlowFixMe[cannot-resolve-module]
+const dynamicFeatureFlags = require('SchedulerFeatureFlags');
+const {enableProfiling: enableProfilingFeatureFlag} = dynamicFeatureFlags;
+
+export const {
+ userBlockingPriorityTimeout,
+ normalPriorityTimeout,
+ lowPriorityTimeout,
+} = dynamicFeatureFlags;
export const enableSchedulerDebugging = true;
export const enableProfiling: boolean =
__PROFILE__ && enableProfilingFeatureFlag;
diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js
index 2ede92b1c06e0..acf2e6e9b9dcc 100644
--- a/packages/shared/ReactFeatureFlags.js
+++ b/packages/shared/ReactFeatureFlags.js
@@ -130,6 +130,9 @@ export const enableUseDeferredValueInitialArg = __EXPERIMENTAL__;
* Enables an expiration time for retry lanes to avoid starvation.
*/
export const enableRetryLaneExpiration = false;
+export const retryLaneExpirationMs = 5000;
+export const syncLaneExpirationMs = 250;
+export const transitionLaneExpirationMs = 5000;
// -----------------------------------------------------------------------------
// Chopping Block
diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js
index 4d488410a55db..91a518a905154 100644
--- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js
+++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js
@@ -21,7 +21,6 @@ import typeof * as DynamicFlagsType from 'ReactNativeInternalFeatureFlags';
// update the test configuration.
export const alwaysThrottleRetries = __VARIANT__;
-export const disableModulePatternComponents = __VARIANT__;
export const enableDeferRootSchedulingToMicrotask = __VARIANT__;
export const enableUnifiedSyncLane = __VARIANT__;
export const enableUseRefAccessWarning = __VARIANT__;
diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js
index 3d228b88440be..8c8ff2cbf97bb 100644
--- a/packages/shared/forks/ReactFeatureFlags.native-fb.js
+++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js
@@ -19,7 +19,6 @@ import * as dynamicFlags from 'ReactNativeInternalFeatureFlags';
// the exports object every time a flag is read.
export const {
alwaysThrottleRetries,
- disableModulePatternComponents,
enableDeferRootSchedulingToMicrotask,
enableUnifiedSyncLane,
enableUseRefAccessWarning,
@@ -28,6 +27,7 @@ export const {
} = dynamicFlags;
// The rest of the flags are static for better dead code elimination.
+export const disableModulePatternComponents = true;
export const enableDebugTracing = false;
export const enableSchedulingProfiler = __PROFILE__;
export const enableProfilerTimer = __PROFILE__;
@@ -66,7 +66,11 @@ export const enableComponentStackLocations = false;
export const enableLegacyFBSupport = false;
export const enableFilterEmptyStringAttributesDOM = false;
export const enableGetInspectorDataForInstanceInProduction = true;
+
export const enableRetryLaneExpiration = false;
+export const retryLaneExpirationMs = 5000;
+export const syncLaneExpirationMs = 250;
+export const transitionLaneExpirationMs = 5000;
export const createRootStrictEffectsByDefault = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js
index b8203b3b3cbcb..795fab334ee80 100644
--- a/packages/shared/forks/ReactFeatureFlags.native-oss.js
+++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js
@@ -49,7 +49,11 @@ export const enableComponentStackLocations = false;
export const enableLegacyFBSupport = false;
export const enableFilterEmptyStringAttributesDOM = false;
export const enableGetInspectorDataForInstanceInProduction = false;
+
export const enableRetryLaneExpiration = false;
+export const retryLaneExpirationMs = 5000;
+export const syncLaneExpirationMs = 250;
+export const transitionLaneExpirationMs = 5000;
export const createRootStrictEffectsByDefault = false;
export const enableUseRefAccessWarning = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js
index 611160e2a1f6a..e0216e3f57535 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js
@@ -49,7 +49,11 @@ export const enableComponentStackLocations = true;
export const enableLegacyFBSupport = false;
export const enableFilterEmptyStringAttributesDOM = false;
export const enableGetInspectorDataForInstanceInProduction = false;
+
export const enableRetryLaneExpiration = false;
+export const retryLaneExpirationMs = 5000;
+export const syncLaneExpirationMs = 250;
+export const transitionLaneExpirationMs = 5000;
export const createRootStrictEffectsByDefault = false;
export const enableUseRefAccessWarning = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
index 60a15318c7c00..93d09f741601e 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
@@ -51,7 +51,11 @@ export const enableUseEffectEventHook = false;
export const enableClientRenderFallbackOnTextMismatch = true;
export const createRootStrictEffectsByDefault = false;
export const enableUseRefAccessWarning = false;
+
export const enableRetryLaneExpiration = false;
+export const retryLaneExpirationMs = 5000;
+export const syncLaneExpirationMs = 250;
+export const transitionLaneExpirationMs = 5000;
export const disableSchedulerTimeoutInWorkLoop = false;
export const enableLazyContextPropagation = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
index c5678792313ae..d5fa0454eaaf0 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
@@ -49,7 +49,11 @@ export const enableComponentStackLocations = true;
export const enableLegacyFBSupport = false;
export const enableFilterEmptyStringAttributesDOM = true;
export const enableGetInspectorDataForInstanceInProduction = false;
+
export const enableRetryLaneExpiration = false;
+export const retryLaneExpirationMs = 5000;
+export const syncLaneExpirationMs = 250;
+export const transitionLaneExpirationMs = 5000;
export const createRootStrictEffectsByDefault = false;
export const enableUseRefAccessWarning = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js
index b824c9ac8323c..74c0ab2f6f5fd 100644
--- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js
+++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js
@@ -29,7 +29,11 @@ export const enableAsyncActions = __VARIANT__;
export const alwaysThrottleRetries = __VARIANT__;
export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__;
export const enableUseDeferredValueInitialArg = __VARIANT__;
+
export const enableRetryLaneExpiration = __VARIANT__;
+export const retryLaneExpirationMs = 5000;
+export const syncLaneExpirationMs = 250;
+export const transitionLaneExpirationMs = 5000;
// Enable this flag to help with concurrent mode debugging.
// It logs information to the console about React scheduling, rendering, and commit phases.
diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js
index 9f7724d0771c0..a76277e43b864 100644
--- a/packages/shared/forks/ReactFeatureFlags.www.js
+++ b/packages/shared/forks/ReactFeatureFlags.www.js
@@ -33,6 +33,9 @@ export const {
enableDO_NOT_USE_disableStrictPassiveEffect,
disableSchedulerTimeoutInWorkLoop,
enableUseDeferredValueInitialArg,
+ retryLaneExpirationMs,
+ syncLaneExpirationMs,
+ transitionLaneExpirationMs,
} = dynamicFeatureFlags;
// On WWW, __EXPERIMENTAL__ is used for a new modern build.
diff --git a/packages/use-subscription/src/__tests__/useSubscription-test.js b/packages/use-subscription/src/__tests__/useSubscription-test.js
index 19eba0a15be8e..9c971bd14bbb3 100644
--- a/packages/use-subscription/src/__tests__/useSubscription-test.js
+++ b/packages/use-subscription/src/__tests__/useSubscription-test.js
@@ -84,7 +84,7 @@ describe('useSubscription', () => {
await act(() => {
renderer = ReactTestRenderer.create(
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
assertLog(['default']);
@@ -136,7 +136,7 @@ describe('useSubscription', () => {
await act(() => {
renderer = ReactTestRenderer.create(
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
assertLog(['initial']);
@@ -185,7 +185,7 @@ describe('useSubscription', () => {
await act(() => {
renderer = ReactTestRenderer.create(
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
@@ -244,7 +244,7 @@ describe('useSubscription', () => {
await act(() => {
renderer = ReactTestRenderer.create(
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
@@ -331,7 +331,7 @@ describe('useSubscription', () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
assertLog(['Child: a-0', 'Grandchild: a-0']);
@@ -434,7 +434,7 @@ describe('useSubscription', () => {
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(, {
- unstable_isConcurrent: true,
+ isConcurrent: true,
});
});
assertLog(['Child: a-0', 'Grandchild: a-0']);
@@ -532,7 +532,7 @@ describe('useSubscription', () => {
await act(() => {
renderer = ReactTestRenderer.create(
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
assertLog([true]);
@@ -566,7 +566,7 @@ describe('useSubscription', () => {
await act(() => {
renderer = ReactTestRenderer.create(
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
});
await waitForAll([]);
@@ -607,7 +607,7 @@ describe('useSubscription', () => {
,
- {unstable_isConcurrent: true},
+ {isConcurrent: true},
);
await waitForAll(['render:first:A', 'render:second:A']);
diff --git a/scripts/flow/xplat.js b/scripts/flow/xplat.js
index fadbe3161aa26..b2c4709a3b566 100644
--- a/scripts/flow/xplat.js
+++ b/scripts/flow/xplat.js
@@ -9,7 +9,6 @@
declare module 'ReactNativeInternalFeatureFlags' {
declare export var alwaysThrottleRetries: boolean;
- declare export var disableModulePatternComponents: boolean;
declare export var enableDeferRootSchedulingToMicrotask: boolean;
declare export var enableUnifiedSyncLane: boolean;
declare export var enableUseRefAccessWarning: boolean;
diff --git a/scripts/print-warnings/print-warnings.js b/scripts/print-warnings/print-warnings.js
index 95cc882cb7724..69b986b3a0d58 100644
--- a/scripts/print-warnings/print-warnings.js
+++ b/scripts/print-warnings/print-warnings.js
@@ -75,19 +75,23 @@ gs([
'!**/node_modules/**/*.js',
]).pipe(
through.obj(transform, cb => {
- if (process.argv[2] === '--js') {
- const warningsArray = Array.from(warnings);
- warningsArray.sort();
- process.stdout.write(
- `export default ${JSON.stringify(warningsArray, null, 2)};\n`
- );
- } else {
- process.stdout.write(
- Array.from(warnings, warning => JSON.stringify(warning))
- .sort()
- .join('\n') + '\n'
- );
- }
+ const warningsArray = Array.from(warnings);
+ warningsArray.sort();
+ process.stdout.write(
+ `/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow strict
+ * @noformat
+ * @oncall react_core
+ */
+
+export default ${JSON.stringify(warningsArray, null, 2)};
+`
+ );
cb();
})
);