Skip to content

Commit 62afb0f

Browse files
committed
Support hidden deprioritization in Batched Mode
Hidden trees will tear and commit in a separate render, as in Concurrent Mode. Unlike Concurrent Mode, once the hidden tree begins, it will finish without yielding.
1 parent 24c6edf commit 62afb0f

File tree

3 files changed

+49
-8
lines changed

3 files changed

+49
-8
lines changed

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,7 @@ import {
8282
Never,
8383
computeAsyncExpiration,
8484
} from './ReactFiberExpirationTime';
85-
import {
86-
ConcurrentMode,
87-
NoMode,
88-
ProfileMode,
89-
StrictMode,
90-
BatchedMode,
91-
} from './ReactTypeOfMode';
85+
import {NoMode, ProfileMode, StrictMode, BatchedMode} from './ReactTypeOfMode';
9286
import {
9387
shouldSetTextContent,
9488
shouldDeprioritizeSubtree,
@@ -963,7 +957,7 @@ function updateHostComponent(current, workInProgress, renderExpirationTime) {
963957
// Check the host config to see if the children are offscreen/hidden.
964958
if (
965959
renderExpirationTime !== Never &&
966-
workInProgress.mode & ConcurrentMode &&
960+
workInProgress.mode & BatchedMode &&
967961
shouldDeprioritizeSubtree(type, nextProps)
968962
) {
969963
// Schedule this fiber to re-render at offscreen priority. Then bailout.

packages/react-reconciler/src/ReactFiberScheduler.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import {
6262
BatchedMode,
6363
ConcurrentMode,
6464
} from './ReactTypeOfMode';
65+
import {ConcurrentRoot} from 'shared/ReactRootTags';
6566
import {
6667
HostRoot,
6768
ClassComponent,
@@ -725,6 +726,10 @@ function renderRoot(
725726
'Should not already be working.',
726727
);
727728

729+
if (root.tag !== ConcurrentRoot) {
730+
isSync = true;
731+
}
732+
728733
if (enableUserTimingAPI && expirationTime !== Sync) {
729734
const didExpire = isSync;
730735
stopRequestCallbackTimer(didExpire);

packages/react-reconciler/src/__tests__/ReactBatchedMode-test.internal.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,46 @@ describe('ReactBatchedMode', () => {
163163
expect(Scheduler).toFlushExpired(['A1']);
164164
expect(root).toMatchRenderedOutput('A1B1');
165165
});
166+
167+
it('hidden subtrees are deprioritized but not yieldy', () => {
168+
const {useEffect} = React;
169+
170+
const root = ReactNoop.createSyncRoot();
171+
function App() {
172+
useEffect(() => Scheduler.yieldValue('Commit'));
173+
return (
174+
<Suspense fallback={<Text text="Loading..." />}>
175+
<div hidden={true}>
176+
<Text text="A" />
177+
<Text text="B" />
178+
<Text text="C" />
179+
</div>
180+
<div>
181+
<Text text="D" />
182+
<Text text="E" />
183+
<Text text="F" />
184+
</div>
185+
</Suspense>
186+
);
187+
}
188+
189+
root.render(<App />);
190+
expect(Scheduler).toFlushAndYieldThrough(['D', 'E', 'F', 'Commit']);
191+
expect(root).toMatchRenderedOutput(
192+
<React.Fragment>
193+
<div hidden={true} />
194+
<div>DEF</div>
195+
</React.Fragment>,
196+
);
197+
198+
Scheduler.unstable_flushNumberOfYields(1);
199+
expect(Scheduler).toHaveYielded(['A', 'B', 'C']);
200+
Scheduler.flushAll();
201+
expect(root).toMatchRenderedOutput(
202+
<React.Fragment>
203+
<div hidden={true}>ABC</div>
204+
<div>DEF</div>
205+
</React.Fragment>,
206+
);
207+
});
166208
});

0 commit comments

Comments
 (0)