Skip to content

Commit 7bac760

Browse files
committed
Revert "Flush discrete passive effects before paint (#21150)"
This reverts commit 2e7acee. If a discrete render results in passive effects, we should flush them synchronously at the end of the current task so that the result is immediately observable. For example, if a passive effect adds an event listener, the listener will be added before the next input. We don't need to do this for effects that don't have discrete/sync priority, because we assume they are not order-dependent and do not need to be observed by external systems. For legacy mode, we will maintain the existing behavior, since it hasn't been reported as an issue, and we'd have to do additional work to distinguish "legacy default sync" from "discrete sync" to prevent all passive effects from being treated this way.
1 parent 207d4c3 commit 7bac760

File tree

4 files changed

+2
-104
lines changed

4 files changed

+2
-104
lines changed

packages/react-reconciler/src/ReactFiberWorkLoop.new.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,21 +1976,6 @@ function commitRootImpl(root, renderPriorityLevel) {
19761976
return null;
19771977
}
19781978

1979-
// If the passive effects are the result of a discrete render, flush them
1980-
// synchronously at the end of the current task so that the result is
1981-
// immediately observable. Otherwise, we assume that they are not
1982-
// order-dependent and do not need to be observed by external systems, so we
1983-
// can wait until after paint.
1984-
// TODO: We can optimize this by not scheduling the callback earlier. Since we
1985-
// currently schedule the callback in multiple places, will wait until those
1986-
// are consolidated.
1987-
if (
1988-
includesSomeLane(pendingPassiveEffectsLanes, SyncLane) &&
1989-
root.tag !== LegacyRoot
1990-
) {
1991-
flushPassiveEffects();
1992-
}
1993-
19941979
// If layout work was scheduled, flush it now.
19951980
flushSyncCallbacks();
19961981

packages/react-reconciler/src/ReactFiberWorkLoop.old.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,21 +1976,6 @@ function commitRootImpl(root, renderPriorityLevel) {
19761976
return null;
19771977
}
19781978

1979-
// If the passive effects are the result of a discrete render, flush them
1980-
// synchronously at the end of the current task so that the result is
1981-
// immediately observable. Otherwise, we assume that they are not
1982-
// order-dependent and do not need to be observed by external systems, so we
1983-
// can wait until after paint.
1984-
// TODO: We can optimize this by not scheduling the callback earlier. Since we
1985-
// currently schedule the callback in multiple places, will wait until those
1986-
// are consolidated.
1987-
if (
1988-
includesSomeLane(pendingPassiveEffectsLanes, SyncLane) &&
1989-
root.tag !== LegacyRoot
1990-
) {
1991-
flushPassiveEffects();
1992-
}
1993-
19941979
// If layout work was scheduled, flush it now.
19951980
flushSyncCallbacks();
19961981

packages/react-reconciler/src/__tests__/ReactFlushSync-test.js

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -61,73 +61,4 @@ describe('ReactFlushSync', () => {
6161
});
6262
expect(root).toMatchRenderedOutput('1, 1');
6363
});
64-
65-
test('flushes passive effects synchronously when they are the result of a sync render', async () => {
66-
function App() {
67-
useEffect(() => {
68-
Scheduler.unstable_yieldValue('Effect');
69-
}, []);
70-
return <Text text="Child" />;
71-
}
72-
73-
const root = ReactNoop.createRoot();
74-
await ReactNoop.act(async () => {
75-
ReactNoop.flushSync(() => {
76-
root.render(<App />);
77-
});
78-
expect(Scheduler).toHaveYielded([
79-
'Child',
80-
// Because the pending effect was the result of a sync update, calling
81-
// flushSync should flush it.
82-
'Effect',
83-
]);
84-
expect(root).toMatchRenderedOutput('Child');
85-
});
86-
});
87-
88-
test('do not flush passive effects synchronously in legacy mode', async () => {
89-
function App() {
90-
useEffect(() => {
91-
Scheduler.unstable_yieldValue('Effect');
92-
}, []);
93-
return <Text text="Child" />;
94-
}
95-
96-
const root = ReactNoop.createLegacyRoot();
97-
await ReactNoop.act(async () => {
98-
ReactNoop.flushSync(() => {
99-
root.render(<App />);
100-
});
101-
expect(Scheduler).toHaveYielded([
102-
'Child',
103-
// Because we're in legacy mode, we shouldn't have flushed the passive
104-
// effects yet.
105-
]);
106-
expect(root).toMatchRenderedOutput('Child');
107-
});
108-
// Effect flushes after paint.
109-
expect(Scheduler).toHaveYielded(['Effect']);
110-
});
111-
112-
test("do not flush passive effects synchronously when they aren't the result of a sync render", async () => {
113-
function App() {
114-
useEffect(() => {
115-
Scheduler.unstable_yieldValue('Effect');
116-
}, []);
117-
return <Text text="Child" />;
118-
}
119-
120-
const root = ReactNoop.createRoot();
121-
await ReactNoop.act(async () => {
122-
root.render(<App />);
123-
expect(Scheduler).toFlushUntilNextPaint([
124-
'Child',
125-
// Because the passive effect was not the result of a sync update, it
126-
// should not flush before paint.
127-
]);
128-
expect(root).toMatchRenderedOutput('Child');
129-
});
130-
// Effect flushes after paint.
131-
expect(Scheduler).toHaveYielded(['Effect']);
132-
});
13364
});

packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ let useDeferredValue;
3232
let forwardRef;
3333
let memo;
3434
let act;
35-
let ContinuousEventPriority;
3635

3736
describe('ReactHooksWithNoopRenderer', () => {
3837
beforeEach(() => {
@@ -56,8 +55,6 @@ describe('ReactHooksWithNoopRenderer', () => {
5655
useDeferredValue = React.unstable_useDeferredValue;
5756
Suspense = React.Suspense;
5857
act = ReactNoop.act;
59-
ContinuousEventPriority = require('react-reconciler/constants')
60-
.ContinuousEventPriority;
6158

6259
textCache = new Map();
6360

@@ -1400,10 +1397,10 @@ describe('ReactHooksWithNoopRenderer', () => {
14001397
expect(Scheduler).toFlushAndYieldThrough(['Child one render']);
14011398

14021399
// Schedule unmount for the parent that unmounts children with pending update.
1403-
ReactNoop.unstable_runWithPriority(ContinuousEventPriority, () => {
1400+
ReactNoop.flushSync(() => {
14041401
setParentState(false);
14051402
});
1406-
expect(Scheduler).toFlushUntilNextPaint([
1403+
expect(Scheduler).toHaveYielded([
14071404
'Parent false render',
14081405
'Parent false commit',
14091406
]);

0 commit comments

Comments
 (0)