Revert recent hydration changes (#25812)

We're reverting the stack of changes that this code belongs to in order
to unblock the sync to Meta's internal codebase. We will attempt to
re-land once the sync is unblocked.

I have not yet verified that this fixes the error that were reported
internally. I will do that before landing.
This commit is contained in:
Andrew Clark
2022-12-05 16:10:03 -05:00
committed by GitHub
parent 2ccfa657d9
commit d807eb52cf
7 changed files with 412 additions and 547 deletions
File diff suppressed because it is too large Load Diff
@@ -613,6 +613,7 @@ describe('Timeline profiler', () => {
`);
});
// @reactVersion >= 18.0
it('should process a sample legacy render sequence', async () => {
utils.legacyRender(<div />, document.createElement('div'));
@@ -628,7 +629,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.01,
"lanes": "0b0000000000000000000000000000001",
"lanes": "0b0000000000000000000000000000000",
"timestamp": 0.006,
"type": "render-idle",
},
@@ -636,7 +637,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.001,
"lanes": "0b0000000000000000000000000000001",
"lanes": "0b0000000000000000000000000000000",
"timestamp": 0.006,
"type": "render",
},
@@ -644,7 +645,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.008,
"lanes": "0b0000000000000000000000000000001",
"lanes": "0b0000000000000000000000000000000",
"timestamp": 0.008,
"type": "commit",
},
@@ -652,7 +653,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 1,
"duration": 0.001,
"lanes": "0b0000000000000000000000000000001",
"lanes": "0b0000000000000000000000000000000",
"timestamp": 0.014,
"type": "layout-effects",
},
@@ -713,13 +714,12 @@ describe('Timeline profiler', () => {
30 => "Offscreen",
},
"laneToReactMeasureMap": Map {
0 => Array [],
1 => Array [
0 => Array [
Object {
"batchUID": 0,
"depth": 0,
"duration": 0.01,
"lanes": "0b0000000000000000000000000000001",
"lanes": "0b0000000000000000000000000000000",
"timestamp": 0.006,
"type": "render-idle",
},
@@ -727,7 +727,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.001,
"lanes": "0b0000000000000000000000000000001",
"lanes": "0b0000000000000000000000000000000",
"timestamp": 0.006,
"type": "render",
},
@@ -735,7 +735,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.008,
"lanes": "0b0000000000000000000000000000001",
"lanes": "0b0000000000000000000000000000000",
"timestamp": 0.008,
"type": "commit",
},
@@ -743,11 +743,12 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 1,
"duration": 0.001,
"lanes": "0b0000000000000000000000000000001",
"lanes": "0b0000000000000000000000000000000",
"timestamp": 0.014,
"type": "layout-effects",
},
],
1 => Array [],
2 => Array [],
3 => Array [],
4 => Array [],
@@ -784,7 +785,7 @@ describe('Timeline profiler', () => {
"reactVersion": "<filtered-version>",
"schedulingEvents": Array [
Object {
"lanes": "0b0000000000000000000000000000001",
"lanes": "0b0000000000000000000000000000000",
"timestamp": 0.005,
"type": "schedule-render",
"warning": null,
@@ -799,6 +800,7 @@ describe('Timeline profiler', () => {
`);
});
// @reactVersion >= 18.0
it('should process a sample createRoot render sequence', async () => {
function App() {
const [didMount, setDidMount] = React.useState(false);
@@ -825,7 +827,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.012,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.006,
"type": "render-idle",
},
@@ -833,7 +835,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.003,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.006,
"type": "render",
},
@@ -841,7 +843,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.008,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.01,
"type": "commit",
},
@@ -849,7 +851,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 1,
"duration": 0.001,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.016,
"type": "layout-effects",
},
@@ -857,7 +859,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.004,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.019,
"type": "passive-effects",
},
@@ -867,7 +869,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0.012,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.024,
"type": "render-idle",
},
@@ -875,7 +877,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0.003,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.024,
"type": "render",
},
@@ -883,7 +885,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0.008,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.028,
"type": "commit",
},
@@ -891,7 +893,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 1,
"duration": 0.001,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.034,
"type": "layout-effects",
},
@@ -899,7 +901,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0.003,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.037,
"type": "passive-effects",
},
@@ -993,13 +995,12 @@ describe('Timeline profiler', () => {
1 => Array [],
2 => Array [],
3 => Array [],
4 => Array [],
5 => Array [
4 => Array [
Object {
"batchUID": 0,
"depth": 0,
"duration": 0.012,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.006,
"type": "render-idle",
},
@@ -1007,7 +1008,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.003,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.006,
"type": "render",
},
@@ -1015,7 +1016,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.008,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.01,
"type": "commit",
},
@@ -1023,7 +1024,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 1,
"duration": 0.001,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.016,
"type": "layout-effects",
},
@@ -1031,7 +1032,7 @@ describe('Timeline profiler', () => {
"batchUID": 0,
"depth": 0,
"duration": 0.004,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.019,
"type": "passive-effects",
},
@@ -1039,7 +1040,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0.012,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.024,
"type": "render-idle",
},
@@ -1047,7 +1048,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0.003,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.024,
"type": "render",
},
@@ -1055,7 +1056,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0.008,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.028,
"type": "commit",
},
@@ -1063,7 +1064,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 1,
"duration": 0.001,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.034,
"type": "layout-effects",
},
@@ -1071,11 +1072,12 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0.003,
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.037,
"type": "passive-effects",
},
],
5 => Array [],
6 => Array [],
7 => Array [],
8 => Array [],
@@ -1108,14 +1110,14 @@ describe('Timeline profiler', () => {
"reactVersion": "<filtered-version>",
"schedulingEvents": Array [
Object {
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.005,
"type": "schedule-render",
"warning": null,
},
Object {
"componentName": "App",
"lanes": "0b0000000000000000000000000000101",
"lanes": "0b0000000000000000000000000000100",
"timestamp": 0.021,
"type": "schedule-state-update",
"warning": null,
@@ -1945,6 +1947,7 @@ describe('Timeline profiler', () => {
global.IS_REACT_ACT_ENVIRONMENT = true;
});
// @reactVersion >= 18.0
it('should process a sample legacy render sequence', async () => {
utils.legacyRender(<div />, document.createElement('div'));
utils.act(() => store.profilerStore.stopProfiling());
@@ -1960,7 +1963,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000000010",
"lanes": "0b0000000000000000000000000000001",
"timestamp": 10,
"type": "render-idle",
},
@@ -1968,7 +1971,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000000010",
"lanes": "0b0000000000000000000000000000001",
"timestamp": 10,
"type": "render",
},
@@ -1976,7 +1979,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000000010",
"lanes": "0b0000000000000000000000000000001",
"timestamp": 10,
"type": "commit",
},
@@ -1984,7 +1987,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 1,
"duration": 0,
"lanes": "0b0000000000000000000000000000010",
"lanes": "0b0000000000000000000000000000001",
"timestamp": 10,
"type": "layout-effects",
},
@@ -1995,13 +1998,13 @@ describe('Timeline profiler', () => {
"flamechart": Array [],
"internalModuleSourceToRanges": Map {},
"laneToLabelMap": Map {
1 => "SyncHydrationLane",
2 => "Sync",
4 => "InputContinuousHydration",
8 => "InputContinuous",
16 => "DefaultHydration",
32 => "Default",
64 => "TransitionHydration",
1 => "Sync",
2 => "InputContinuousHydration",
4 => "InputContinuous",
8 => "DefaultHydration",
16 => "Default",
32 => "TransitionHydration",
64 => "Transition",
128 => "Transition",
256 => "Transition",
512 => "Transition",
@@ -2017,7 +2020,7 @@ describe('Timeline profiler', () => {
524288 => "Transition",
1048576 => "Transition",
2097152 => "Transition",
4194304 => "Transition",
4194304 => "Retry",
8388608 => "Retry",
16777216 => "Retry",
33554432 => "Retry",
@@ -2028,13 +2031,12 @@ describe('Timeline profiler', () => {
1073741824 => "Offscreen",
},
"laneToReactMeasureMap": Map {
1 => Array [],
2 => Array [
1 => Array [
Object {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000000010",
"lanes": "0b0000000000000000000000000000001",
"timestamp": 10,
"type": "render-idle",
},
@@ -2042,7 +2044,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000000010",
"lanes": "0b0000000000000000000000000000001",
"timestamp": 10,
"type": "render",
},
@@ -2050,7 +2052,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000000010",
"lanes": "0b0000000000000000000000000000001",
"timestamp": 10,
"type": "commit",
},
@@ -2058,11 +2060,12 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 1,
"duration": 0,
"lanes": "0b0000000000000000000000000000010",
"lanes": "0b0000000000000000000000000000001",
"timestamp": 10,
"type": "layout-effects",
},
],
2 => Array [],
4 => Array [],
8 => Array [],
16 => Array [],
@@ -2099,7 +2102,7 @@ describe('Timeline profiler', () => {
"reactVersion": "<filtered-version>",
"schedulingEvents": Array [
Object {
"lanes": "0b0000000000000000000000000000010",
"lanes": "0b0000000000000000000000000000001",
"timestamp": 10,
"type": "schedule-render",
"warning": null,
@@ -2114,6 +2117,7 @@ describe('Timeline profiler', () => {
`);
});
// @reactVersion >= 18.0
it('should process a sample createRoot render sequence', async () => {
function App() {
const [didMount, setDidMount] = React.useState(false);
@@ -2149,7 +2153,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "render-idle",
},
@@ -2157,7 +2161,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "render",
},
@@ -2165,7 +2169,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "commit",
},
@@ -2173,7 +2177,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 1,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "layout-effects",
},
@@ -2181,7 +2185,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "passive-effects",
},
@@ -2191,7 +2195,7 @@ describe('Timeline profiler', () => {
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "render-idle",
},
@@ -2199,7 +2203,7 @@ describe('Timeline profiler', () => {
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "render",
},
@@ -2207,7 +2211,7 @@ describe('Timeline profiler', () => {
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "commit",
},
@@ -2215,7 +2219,7 @@ describe('Timeline profiler', () => {
"batchUID": 2,
"depth": 1,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "layout-effects",
},
@@ -2223,7 +2227,7 @@ describe('Timeline profiler', () => {
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "passive-effects",
},
@@ -2263,13 +2267,13 @@ describe('Timeline profiler', () => {
"flamechart": Array [],
"internalModuleSourceToRanges": Map {},
"laneToLabelMap": Map {
1 => "SyncHydrationLane",
2 => "Sync",
4 => "InputContinuousHydration",
8 => "InputContinuous",
16 => "DefaultHydration",
32 => "Default",
64 => "TransitionHydration",
1 => "Sync",
2 => "InputContinuousHydration",
4 => "InputContinuous",
8 => "DefaultHydration",
16 => "Default",
32 => "TransitionHydration",
64 => "Transition",
128 => "Transition",
256 => "Transition",
512 => "Transition",
@@ -2285,7 +2289,7 @@ describe('Timeline profiler', () => {
524288 => "Transition",
1048576 => "Transition",
2097152 => "Transition",
4194304 => "Transition",
4194304 => "Retry",
8388608 => "Retry",
16777216 => "Retry",
33554432 => "Retry",
@@ -2300,13 +2304,12 @@ describe('Timeline profiler', () => {
2 => Array [],
4 => Array [],
8 => Array [],
16 => Array [],
32 => Array [
16 => Array [
Object {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "render-idle",
},
@@ -2314,7 +2317,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "render",
},
@@ -2322,7 +2325,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "commit",
},
@@ -2330,7 +2333,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 1,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "layout-effects",
},
@@ -2338,7 +2341,7 @@ describe('Timeline profiler', () => {
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "passive-effects",
},
@@ -2346,7 +2349,7 @@ describe('Timeline profiler', () => {
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "render-idle",
},
@@ -2354,7 +2357,7 @@ describe('Timeline profiler', () => {
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "render",
},
@@ -2362,7 +2365,7 @@ describe('Timeline profiler', () => {
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "commit",
},
@@ -2370,7 +2373,7 @@ describe('Timeline profiler', () => {
"batchUID": 2,
"depth": 1,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "layout-effects",
},
@@ -2378,11 +2381,12 @@ describe('Timeline profiler', () => {
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "passive-effects",
},
],
32 => Array [],
64 => Array [],
128 => Array [],
256 => Array [],
@@ -2415,7 +2419,7 @@ describe('Timeline profiler', () => {
"reactVersion": "<filtered-version>",
"schedulingEvents": Array [
Object {
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "schedule-render",
"warning": null,
@@ -2424,7 +2428,7 @@ describe('Timeline profiler', () => {
"componentName": "App",
"componentStack": "
in App (at **)",
"lanes": "0b0000000000000000000000000100000",
"lanes": "0b0000000000000000000000000010000",
"timestamp": 10,
"type": "schedule-state-update",
"warning": null,
@@ -21,7 +21,6 @@ let Suspense;
let act;
let IdleEventPriority;
let ContinuousEventPriority;
function dispatchMouseHoverEvent(to, from) {
if (!to) {
@@ -111,18 +110,6 @@ function TODO_scheduleIdleDOMSchedulerTask(fn) {
});
}
function TODO_scheduleContinuousSchedulerTask(fn) {
ReactDOM.unstable_runWithPriority(ContinuousEventPriority, () => {
const prevEvent = window.event;
window.event = {type: 'message'};
try {
fn();
} finally {
window.event = prevEvent;
}
});
}
describe('ReactDOMServerSelectiveHydration', () => {
beforeEach(() => {
jest.resetModuleRegistry();
@@ -138,8 +125,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
Suspense = React.Suspense;
IdleEventPriority = require('react-reconciler/constants').IdleEventPriority;
ContinuousEventPriority = require('react-reconciler/constants')
.ContinuousEventPriority;
});
it('hydrates the target boundary synchronously during a click', async () => {
@@ -1511,10 +1496,12 @@ describe('ReactDOMServerSelectiveHydration', () => {
// Start rendering. This will force the first boundary to hydrate
// by scheduling it at one higher pri than Idle.
expect(Scheduler).toFlushAndYieldThrough([
// An update was scheduled to force hydrate the boundary, but React will
// continue rendering at Idle until the next time React yields. This is
// fine though because it will switch to the hydration level when it
// re-enters the work loop.
'App',
// Start hydrating A
'A',
'AA',
]);
// Hover over A which (could) schedule at one higher pri than Idle.
@@ -1785,104 +1772,4 @@ describe('ReactDOMServerSelectiveHydration', () => {
document.body.removeChild(container);
});
it('can force hydration in response to sync update', () => {
function Child({text}) {
Scheduler.unstable_yieldValue(`Child ${text}`);
return <span ref={ref => (spanRef = ref)}>{text}</span>;
}
function App({text}) {
Scheduler.unstable_yieldValue(`App ${text}`);
return (
<div>
<Suspense fallback={null}>
<Child text={text} />
</Suspense>
</div>
);
}
let spanRef;
const finalHTML = ReactDOMServer.renderToString(<App text="A" />);
expect(Scheduler).toHaveYielded(['App A', 'Child A']);
const container = document.createElement('div');
document.body.appendChild(container);
container.innerHTML = finalHTML;
const initialSpan = container.getElementsByTagName('span')[0];
const root = ReactDOMClient.hydrateRoot(container, <App text="A" />);
expect(Scheduler).toFlushUntilNextPaint(['App A']);
ReactDOM.flushSync(() => {
root.render(<App text="B" />);
});
expect(Scheduler).toHaveYielded(['App B', 'Child A', 'App B', 'Child B']);
expect(initialSpan).toBe(spanRef);
});
// @gate experimental || www
it('can force hydration in response to continuous update', () => {
function Child({text}) {
Scheduler.unstable_yieldValue(`Child ${text}`);
return <span ref={ref => (spanRef = ref)}>{text}</span>;
}
function App({text}) {
Scheduler.unstable_yieldValue(`App ${text}`);
return (
<div>
<Suspense fallback={null}>
<Child text={text} />
</Suspense>
</div>
);
}
let spanRef;
const finalHTML = ReactDOMServer.renderToString(<App text="A" />);
expect(Scheduler).toHaveYielded(['App A', 'Child A']);
const container = document.createElement('div');
document.body.appendChild(container);
container.innerHTML = finalHTML;
const initialSpan = container.getElementsByTagName('span')[0];
const root = ReactDOMClient.hydrateRoot(container, <App text="A" />);
expect(Scheduler).toFlushUntilNextPaint(['App A']);
TODO_scheduleContinuousSchedulerTask(() => {
root.render(<App text="B" />);
});
expect(Scheduler).toFlushAndYield(['App B', 'Child A', 'App B', 'Child B']);
expect(initialSpan).toBe(spanRef);
});
it('can force hydration in response to default update', () => {
function Child({text}) {
Scheduler.unstable_yieldValue(`Child ${text}`);
return <span ref={ref => (spanRef = ref)}>{text}</span>;
}
function App({text}) {
Scheduler.unstable_yieldValue(`App ${text}`);
return (
<div>
<Suspense fallback={null}>
<Child text={text} />
</Suspense>
</div>
);
}
let spanRef;
const finalHTML = ReactDOMServer.renderToString(<App text="A" />);
expect(Scheduler).toHaveYielded(['App A', 'Child A']);
const container = document.createElement('div');
document.body.appendChild(container);
container.innerHTML = finalHTML;
const initialSpan = container.getElementsByTagName('span')[0];
const root = ReactDOMClient.hydrateRoot(container, <App text="A" />);
expect(Scheduler).toFlushUntilNextPaint(['App A']);
ReactDOM.unstable_batchedUpdates(() => {
root.render(<App text="B" />);
});
expect(Scheduler).toFlushAndYield(['App B', 'Child A', 'App B', 'Child B']);
expect(initialSpan).toBe(spanRef);
});
});
+6 -26
View File
@@ -282,14 +282,6 @@ import {
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
// A special exception that's used to unwind the stack when an update flows
// into a dehydrated boundary.
export const SelectiveHydrationException: mixed = new Error(
"This is not a real error. It's an implementation detail of React's " +
"selective hydration feature. If this leaks into userspace, it's a bug in " +
'React. Please file an issue.',
);
let didReceiveUpdate: boolean = false;
let didWarnAboutBadClass;
@@ -2868,16 +2860,6 @@ function updateDehydratedSuspenseComponent(
attemptHydrationAtLane,
eventTime,
);
// Throw a special object that signals to the work loop that it should
// interrupt the current render.
//
// Because we're inside a React-only execution stack, we don't
// strictly need to throw here — we could instead modify some internal
// work loop state. But using an exception means we don't need to
// check for this case on every iteration of the work loop. So doing
// it this way moves the check out of the fast path.
throw SelectiveHydrationException;
} else {
// We have already tried to ping at a higher priority than we're rendering with
// so if we got here, we must have failed to hydrate at those levels. We must
@@ -2888,17 +2870,15 @@ function updateDehydratedSuspenseComponent(
}
}
// If we did not selectively hydrate, we'll continue rendering without
// hydrating. Mark this tree as suspended to prevent it from committing
// outside a transition.
//
// This path should only happen if the hydration lane already suspended.
// Currently, it also happens during sync updates because there is no
// hydration lane for sync updates.
// If we have scheduled higher pri work above, this will just abort the render
// since we now have higher priority work. We'll try to infinitely suspend until
// we yield. TODO: We could probably just force yielding earlier instead.
renderDidSuspendDelayIfPossible();
// If we rendered synchronously, we won't yield so have to render something.
// This will cause us to delete any existing content.
// TODO: We should ideally have a sync hydration lane that we can apply to do
// a pass where we hydrate this subtree in place using the previous Context and then
// reapply the update afterwards.
renderDidSuspendDelayIfPossible();
return retrySuspenseComponentWithoutHydrating(
current,
workInProgress,
+33 -41
View File
@@ -36,39 +36,39 @@ export const TotalLanes = 31;
export const NoLanes: Lanes = /* */ 0b0000000000000000000000000000000;
export const NoLane: Lane = /* */ 0b0000000000000000000000000000000;
export const SyncHydrationLane: Lane = /* */ 0b0000000000000000000000000000001;
export const SyncLane: Lane = /* */ 0b0000000000000000000000000000010;
export const SyncLane: Lane = /* */ 0b0000000000000000000000000000001;
export const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000000100;
export const InputContinuousLane: Lane = /* */ 0b0000000000000000000000000001000;
export const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000000010;
export const InputContinuousLane: Lane = /* */ 0b0000000000000000000000000000100;
export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000000010000;
export const DefaultLane: Lane = /* */ 0b0000000000000000000000000100000;
export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000000001000;
export const DefaultLane: Lane = /* */ 0b0000000000000000000000000010000;
const TransitionHydrationLane: Lane = /* */ 0b0000000000000000000000001000000;
const TransitionLanes: Lanes = /* */ 0b0000000011111111111111110000000;
const TransitionLane1: Lane = /* */ 0b0000000000000000000000010000000;
const TransitionLane2: Lane = /* */ 0b0000000000000000000000100000000;
const TransitionLane3: Lane = /* */ 0b0000000000000000000001000000000;
const TransitionLane4: Lane = /* */ 0b0000000000000000000010000000000;
const TransitionLane5: Lane = /* */ 0b0000000000000000000100000000000;
const TransitionLane6: Lane = /* */ 0b0000000000000000001000000000000;
const TransitionLane7: Lane = /* */ 0b0000000000000000010000000000000;
const TransitionLane8: Lane = /* */ 0b0000000000000000100000000000000;
const TransitionLane9: Lane = /* */ 0b0000000000000001000000000000000;
const TransitionLane10: Lane = /* */ 0b0000000000000010000000000000000;
const TransitionLane11: Lane = /* */ 0b0000000000000100000000000000000;
const TransitionLane12: Lane = /* */ 0b0000000000001000000000000000000;
const TransitionLane13: Lane = /* */ 0b0000000000010000000000000000000;
const TransitionLane14: Lane = /* */ 0b0000000000100000000000000000000;
const TransitionLane15: Lane = /* */ 0b0000000001000000000000000000000;
const TransitionLane16: Lane = /* */ 0b0000000010000000000000000000000;
const TransitionHydrationLane: Lane = /* */ 0b0000000000000000000000000100000;
const TransitionLanes: Lanes = /* */ 0b0000000001111111111111111000000;
const TransitionLane1: Lane = /* */ 0b0000000000000000000000001000000;
const TransitionLane2: Lane = /* */ 0b0000000000000000000000010000000;
const TransitionLane3: Lane = /* */ 0b0000000000000000000000100000000;
const TransitionLane4: Lane = /* */ 0b0000000000000000000001000000000;
const TransitionLane5: Lane = /* */ 0b0000000000000000000010000000000;
const TransitionLane6: Lane = /* */ 0b0000000000000000000100000000000;
const TransitionLane7: Lane = /* */ 0b0000000000000000001000000000000;
const TransitionLane8: Lane = /* */ 0b0000000000000000010000000000000;
const TransitionLane9: Lane = /* */ 0b0000000000000000100000000000000;
const TransitionLane10: Lane = /* */ 0b0000000000000001000000000000000;
const TransitionLane11: Lane = /* */ 0b0000000000000010000000000000000;
const TransitionLane12: Lane = /* */ 0b0000000000000100000000000000000;
const TransitionLane13: Lane = /* */ 0b0000000000001000000000000000000;
const TransitionLane14: Lane = /* */ 0b0000000000010000000000000000000;
const TransitionLane15: Lane = /* */ 0b0000000000100000000000000000000;
const TransitionLane16: Lane = /* */ 0b0000000001000000000000000000000;
const RetryLanes: Lanes = /* */ 0b0000111100000000000000000000000;
const RetryLane1: Lane = /* */ 0b0000000100000000000000000000000;
const RetryLane2: Lane = /* */ 0b0000001000000000000000000000000;
const RetryLane3: Lane = /* */ 0b0000010000000000000000000000000;
const RetryLane4: Lane = /* */ 0b0000100000000000000000000000000;
const RetryLanes: Lanes = /* */ 0b0000111110000000000000000000000;
const RetryLane1: Lane = /* */ 0b0000000010000000000000000000000;
const RetryLane2: Lane = /* */ 0b0000000100000000000000000000000;
const RetryLane3: Lane = /* */ 0b0000001000000000000000000000000;
const RetryLane4: Lane = /* */ 0b0000010000000000000000000000000;
const RetryLane5: Lane = /* */ 0b0000100000000000000000000000000;
export const SomeRetryLane: Lane = RetryLane1;
@@ -85,9 +85,6 @@ export const OffscreenLane: Lane = /* */ 0b1000000000000000000
// It should be kept in sync with the Lanes values above.
export function getLabelForLane(lane: Lane): string | void {
if (enableSchedulingProfiler) {
if (lane & SyncHydrationLane) {
return 'SyncHydrationLane';
}
if (lane & SyncLane) {
return 'Sync';
}
@@ -134,8 +131,6 @@ let nextRetryLane: Lane = RetryLane1;
function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes {
switch (getHighestPriorityLane(lanes)) {
case SyncHydrationLane:
return SyncHydrationLane;
case SyncLane:
return SyncLane;
case InputContinuousHydrationLane:
@@ -169,6 +164,7 @@ function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes {
case RetryLane2:
case RetryLane3:
case RetryLane4:
case RetryLane5:
return lanes & RetryLanes;
case SelectiveHydrationLane:
return SelectiveHydrationLane;
@@ -331,7 +327,6 @@ export function getMostRecentEventTime(root: FiberRoot, lanes: Lanes): number {
function computeExpirationTime(lane: Lane, currentTime: number) {
switch (lane) {
case SyncHydrationLane:
case SyncLane:
case InputContinuousHydrationLane:
case InputContinuousLane:
@@ -369,6 +364,7 @@ function computeExpirationTime(lane: Lane, currentTime: number) {
case RetryLane2:
case RetryLane3:
case RetryLane4:
case RetryLane5:
// TODO: Retries should be allowed to expire if they are CPU bound for
// too long, but when I made this change it caused a spike in browser
// crashes. There must be some other underlying bug; not super urgent but
@@ -463,7 +459,7 @@ export function getLanesToRetrySynchronouslyOnError(
}
export function includesSyncLane(lanes: Lanes): boolean {
return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes;
return (lanes & SyncLane) !== NoLanes;
}
export function includesNonIdleWork(lanes: Lanes): boolean {
@@ -473,8 +469,6 @@ export function includesOnlyRetries(lanes: Lanes): boolean {
return (lanes & RetryLanes) === lanes;
}
export function includesOnlyNonUrgentLanes(lanes: Lanes): boolean {
// TODO: Should hydration lanes be included here? This function is only
// used in `updateDeferredValueImpl`.
const UrgentLanes = SyncLane | InputContinuousLane | DefaultLane;
return (lanes & UrgentLanes) === NoLanes;
}
@@ -755,9 +749,6 @@ export function getBumpedLaneForHydration(
let lane;
switch (renderLane) {
case SyncLane:
lane = SyncHydrationLane;
break;
case InputContinuousLane:
lane = InputContinuousHydrationLane;
break;
@@ -784,6 +775,7 @@ export function getBumpedLaneForHydration(
case RetryLane2:
case RetryLane3:
case RetryLane4:
case RetryLane5:
lane = TransitionHydrationLane;
break;
case IdleLane:
+16 -47
View File
@@ -138,7 +138,7 @@ import {
NoTimestamp,
claimNextTransitionLane,
claimNextRetryLane,
includesSyncLane,
includesSomeLane,
isSubsetOfLanes,
mergeLanes,
removeLanes,
@@ -175,7 +175,6 @@ import {
} from './ReactEventPriorities';
import {requestCurrentTransition, NoTransition} from './ReactFiberTransition';
import {
SelectiveHydrationException,
beginWork as originalBeginWork,
replayFunctionComponent,
} from './ReactFiberBeginWork';
@@ -317,14 +316,13 @@ let workInProgress: Fiber | null = null;
// The lanes we're rendering
let workInProgressRootRenderLanes: Lanes = NoLanes;
opaque type SuspendedReason = 0 | 1 | 2 | 3 | 4 | 5 | 6;
opaque type SuspendedReason = 0 | 1 | 2 | 3 | 4 | 5;
const NotSuspended: SuspendedReason = 0;
const SuspendedOnError: SuspendedReason = 1;
const SuspendedOnData: SuspendedReason = 2;
const SuspendedOnImmediate: SuspendedReason = 3;
const SuspendedOnDeprecatedThrowPromise: SuspendedReason = 4;
const SuspendedAndReadyToUnwind: SuspendedReason = 5;
const SuspendedOnHydration: SuspendedReason = 6;
// When this is true, the work-in-progress fiber just suspended (or errored) and
// we've yet to unwind the stack. In some cases, we may yield to the main thread
@@ -915,7 +913,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
// TODO: Temporary until we confirm this warning is not fired.
if (
existingCallbackNode == null &&
!includesSyncLane(existingCallbackPriority)
existingCallbackPriority !== SyncLane
) {
console.error(
'Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue.',
@@ -933,7 +931,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
// Schedule a new callback.
let newCallbackNode;
if (includesSyncLane(newCallbackPriority)) {
if (newCallbackPriority === SyncLane) {
// Special case: Sync React callbacks are scheduled on a special
// internal queue
if (root.tag === LegacyRoot) {
@@ -1477,7 +1475,7 @@ function performSyncWorkOnRoot(root) {
flushPassiveEffects();
let lanes = getNextLanes(root, NoLanes);
if (!includesSyncLane(lanes)) {
if (!includesSomeLane(lanes, SyncLane)) {
// There's no remaining sync work left.
ensureRootIsScheduled(root, now());
return null;
@@ -1799,17 +1797,6 @@ function handleThrow(root, thrownValue): void {
workInProgressSuspendedReason = shouldAttemptToSuspendUntilDataResolves()
? SuspendedOnData
: SuspendedOnImmediate;
} else if (thrownValue === SelectiveHydrationException) {
// An update flowed into a dehydrated boundary. Before we can apply the
// update, we need to finish hydrating. Interrupt the work-in-progress
// render so we can restart at the hydration lane.
//
// The ideal implementation would be able to switch contexts without
// unwinding the current stack.
//
// We could name this something more general but as of now it's the only
// case where we think this should happen.
workInProgressSuspendedReason = SuspendedOnHydration;
} else {
// This is a regular error.
const isWakeable =
@@ -2051,7 +2038,7 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) {
markRenderStarted(lanes);
}
outer: do {
do {
try {
if (
workInProgressSuspendedReason !== NotSuspended &&
@@ -2067,23 +2054,11 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) {
// function and fork the behavior some other way.
const unitOfWork = workInProgress;
const thrownValue = workInProgressThrownValue;
switch (workInProgressSuspendedReason) {
case SuspendedOnHydration: {
// Selective hydration. An update flowed into a dehydrated tree.
// Interrupt the current render so the work loop can switch to the
// hydration lane.
workInProgress = null;
workInProgressRootExitStatus = RootDidNotComplete;
break outer;
}
default: {
// Continue with the normal work loop.
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
unwindSuspendedUnitOfWork(unitOfWork, thrownValue);
break;
}
}
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
unwindSuspendedUnitOfWork(unitOfWork, thrownValue);
// Continue with the normal work loop.
}
workLoopSync();
break;
@@ -2241,14 +2216,6 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
unwindSuspendedUnitOfWork(unitOfWork, thrownValue);
break;
}
case SuspendedOnHydration: {
// Selective hydration. An update flowed into a dehydrated tree.
// Interrupt the current render so the work loop can switch to the
// hydration lane.
workInProgress = null;
workInProgressRootExitStatus = RootDidNotComplete;
break outer;
}
default: {
throw new Error(
'Unexpected SuspendedReason. This is a bug in React.',
@@ -2927,13 +2894,16 @@ function commitRootImpl(
// TODO: We can optimize this by not scheduling the callback earlier. Since we
// currently schedule the callback in multiple places, will wait until those
// are consolidated.
if (includesSyncLane(pendingPassiveEffectsLanes) && root.tag !== LegacyRoot) {
if (
includesSomeLane(pendingPassiveEffectsLanes, SyncLane) &&
root.tag !== LegacyRoot
) {
flushPassiveEffects();
}
// Read this again, since a passive effect might have updated it
remainingLanes = root.pendingLanes;
if (includesSyncLane(remainingLanes)) {
if (includesSomeLane(remainingLanes, (SyncLane: Lane))) {
if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
markNestedUpdateScheduled();
}
@@ -3771,7 +3741,6 @@ if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {
if (
didSuspendOrErrorWhileHydratingDEV() ||
originalError === SuspenseException ||
originalError === SelectiveHydrationException ||
(originalError !== null &&
typeof originalError === 'object' &&
typeof originalError.then === 'function')
@@ -16,9 +16,8 @@ describe('DebugTracing', () => {
let logs;
const SYNC_LANE_STRING = '0b0000000000000000000000000000010';
const DEFAULT_LANE_STRING = '0b0000000000000000000000000100000';
const RETRY_LANE_STRING = '0b0000000100000000000000000000000';
const DEFAULT_LANE_STRING = '0b0000000000000000000000000010000';
const RETRY_LANE_STRING = '0b0000000010000000000000000000000';
global.IS_REACT_ACT_ENVIRONMENT = true;
@@ -88,9 +87,9 @@ describe('DebugTracing', () => {
);
expect(logs).toEqual([
`group: ⚛️ render (${SYNC_LANE_STRING})`,
'group: ⚛️ render (0b0000000000000000000000000000001)',
'log: ⚛️ Example suspended',
`groupEnd: ⚛️ render (${SYNC_LANE_STRING})`,
'groupEnd: ⚛️ render (0b0000000000000000000000000000001)',
]);
logs.splice(0);
@@ -122,9 +121,9 @@ describe('DebugTracing', () => {
);
expect(logs).toEqual([
`group: ⚛️ render (${SYNC_LANE_STRING})`,
'group: ⚛️ render (0b0000000000000000000000000000001)',
'log: <Wrapper/>',
`groupEnd: ⚛️ render (${SYNC_LANE_STRING})`,
'groupEnd: ⚛️ render (0b0000000000000000000000000000001)',
]);
logs.splice(0);
@@ -238,7 +237,7 @@ describe('DebugTracing', () => {
expect(logs).toEqual([
`group: ⚛️ commit (${DEFAULT_LANE_STRING})`,
`group: ⚛️ layout effects (${DEFAULT_LANE_STRING})`,
`log: ⚛️ Example updated state (${SYNC_LANE_STRING})`,
'log: ⚛️ Example updated state (0b0000000000000000000000000000001)',
`groupEnd: ⚛️ layout effects (${DEFAULT_LANE_STRING})`,
`groupEnd: ⚛️ commit (${DEFAULT_LANE_STRING})`,
]);
@@ -296,7 +295,7 @@ describe('DebugTracing', () => {
expect(logs).toEqual([
`group: ⚛️ commit (${DEFAULT_LANE_STRING})`,
`group: ⚛️ layout effects (${DEFAULT_LANE_STRING})`,
`log: ⚛️ Example updated state (${SYNC_LANE_STRING})`,
'log: ⚛️ Example updated state (0b0000000000000000000000000000001)',
`groupEnd: ⚛️ layout effects (${DEFAULT_LANE_STRING})`,
`groupEnd: ⚛️ commit (${DEFAULT_LANE_STRING})`,
]);