Skip to content

Commit 16dbe84

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 cc24d0e commit 16dbe84

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
@@ -83,13 +83,7 @@ import {
8383
Never,
8484
computeAsyncExpiration,
8585
} from './ReactFiberExpirationTime';
86-
import {
87-
ConcurrentMode,
88-
NoMode,
89-
ProfileMode,
90-
StrictMode,
91-
BatchedMode,
92-
} from './ReactTypeOfMode';
86+
import {NoMode, ProfileMode, StrictMode, BatchedMode} from './ReactTypeOfMode';
9387
import {
9488
shouldSetTextContent,
9589
shouldDeprioritizeSubtree,
@@ -974,7 +968,7 @@ function updateHostComponent(current, workInProgress, renderExpirationTime) {
974968
// Check the host config to see if the children are offscreen/hidden.
975969
if (
976970
renderExpirationTime !== Never &&
977-
workInProgress.mode & ConcurrentMode &&
971+
workInProgress.mode & BatchedMode &&
978972
shouldDeprioritizeSubtree(type, nextProps)
979973
) {
980974
// 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,
@@ -728,6 +729,10 @@ function renderRoot(
728729
'Should not already be working.',
729730
);
730731

732+
if (root.tag !== ConcurrentRoot) {
733+
isSync = true;
734+
}
735+
731736
if (enableUserTimingAPI && expirationTime !== Sync) {
732737
const didExpire = isSync;
733738
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)