19
let Suspense;
20
let SuspenseList;
21
let Offscreen;
22
+let useSyncExternalStore;
23
let act;
24
let IdleEventPriority;
25
let waitForAll;
114
Scheduler = require('scheduler');
115
Suspense = React.Suspense;
116
Offscreen = React.unstable_Offscreen;
117
+ useSyncExternalStore = React.useSyncExternalStore;
118
if (gate(flags => flags.enableSuspenseList)) {
119
SuspenseList = React.SuspenseList;
120
}
482
});
483
484
it('recovers with client render when server rendered additional nodes at suspense root', async () => {
485
+ function CheckIfHydrating({children}) {
486
+ // This is a trick to check whether we're hydrating or not, since React
487
+ // doesn't expose that information currently except
488
+ // via useSyncExternalStore.
489
+ let serverOrClient = '(unknown)';
490
+ useSyncExternalStore(
491
+ () => {},
492
+ () => {
493
+ serverOrClient = 'Client rendered';
494
+ return null;
495
+ },
496
+ () => {
497
+ serverOrClient = 'Server rendered';
498
+ return null;
499
+ },
500
+ );
501
+ Scheduler.log(serverOrClient);
502
+ return null;
503
+ }
504
+
505
const ref = React.createRef();
506
function App({hasB}) {
507
return (
509
<Suspense fallback="Loading...">
510
<span ref={ref}>A</span>
511
{hasB ? <span>B</span> : null}
512
+ <CheckIfHydrating />
513
</Suspense>
514
<div>Sibling</div>
515
</div>
517
}
518
519
const finalHTML = ReactDOMServer.renderToString(<App hasB={true} />);
520
+ assertLog(['Server rendered']);
521
522
const container = document.createElement('div');
523
container.innerHTML = finalHTML;
538
});
539
}).toErrorDev('Did not expect server HTML to contain a <span> in <div>');
540
517
- jest.runAllTimers();
518
-
541
expect(container.innerHTML).toContain('<span>A</span>');
542
expect(container.innerHTML).not.toContain('<span>B</span>');
543
544
assertLog([
545
+ 'Server rendered',
546
+ 'Client rendered',
547
'There was an error while hydrating this Suspense boundary. ' +
548
'Switched to client rendering.',
549
]);