10
'use strict';
11
12
let useSyncExternalStore;
13
-let useSyncExternalStoreExtra;
13
+let useSyncExternalStoreWithSelector;
14
let React;
15
let ReactDOM;
16
let Scheduler;
25
beforeEach(() => {
26
jest.resetModules();
27
28
- // Remove the built-in API from the React exports to force the package to
29
- // use the shim.
30
- if (!gate(flags => flags.supportsNativeUseSyncExternalStore)) {
31
- // and the non-variant tests for the shim.
32
- //
28
+ if (gate(flags => flags.enableUseSyncExternalStoreShim)) {
29
// Remove useSyncExternalStore from the React imports so that we use the
30
// shim instead. Also removing startTransition, since we use that to
31
// detect outdated 18 alphas that don't yet include useSyncExternalStore.
38
startTransition: _,
39
// eslint-disable-next-line no-unused-vars
40
useSyncExternalStore: __,
45
- // eslint-disable-next-line no-unused-vars
46
- unstable_useSyncExternalStore: ___,
41
...otherExports
42
} = jest.requireActual('react');
43
return otherExports;
58
// in both concurrent and legacy mode, I'm adding batching here.
59
act = cb => internalAct(() => ReactDOM.unstable_batchedUpdates(cb));
60
67
- useSyncExternalStore = require('use-sync-external-store')
61
+ if (gate(flags => flags.source)) {
62
+ // The `shim/with-selector` module composes the main
63
+ // `use-sync-external-store` entrypoint. In the compiled artifacts, this
64
+ // is resolved to the `shim` implementation by our build config, but when
65
+ // running the tests against the source files, we need to tell Jest how to
66
+ // resolve it. Because this is a source module, this mock has no affect on
67
+ // the build tests.
68
+ jest.mock('use-sync-external-store/src/useSyncExternalStore', () =>
69
+ jest.requireActual('use-sync-external-store/shim'),
70
+ );
71
+ }
72
+ useSyncExternalStore = require('use-sync-external-store/shim')
73
.useSyncExternalStore;
69
- useSyncExternalStoreExtra = require('use-sync-external-store/extra')
70
- .useSyncExternalStoreExtra;
74
+ useSyncExternalStoreWithSelector = require('use-sync-external-store/shim/with-selector')
75
+ .useSyncExternalStoreWithSelector;
76
});
77
78
function Text({text}) {
83
function createRoot(container) {
84
// This wrapper function exists so we can test both legacy roots and
85
// concurrent roots.
81
- if (gate(flags => flags.supportsNativeUseSyncExternalStore)) {
86
+ if (gate(flags => !flags.enableUseSyncExternalStoreShim)) {
87
// The native implementation only exists in 18+, so we test using
88
// concurrent mode. To test the legacy root behavior in the native
89
// implementation (which is supported in the sense that it needs to have
270
271
// In React 18, you can't observe in between a sync render and its
272
// passive effects, so this is only relevant to legacy roots
268
- // @gate !supportsNativeUseSyncExternalStore
273
+ // @gate enableUseSyncExternalStoreShim
274
test(
275
"compares to current state before bailing out, even when there's a " +
276
'mutation in between the sync and passive effects',
552
await act(() => {
553
store.set({value: 1, throwInGetSnapshot: true, throwInIsEqual: false});
554
});
550
- if (gate(flags => flags.supportsNativeUseSyncExternalStore)) {
555
+ if (gate(flags => !flags.enableUseSyncExternalStoreShim)) {
556
expect(Scheduler).toHaveYielded([
557
'Error in getSnapshot',
558
// In a concurrent root, React renders a second time to attempt to
600
601
function App() {
602
Scheduler.unstable_yieldValue('App');
598
- const a = useSyncExternalStoreExtra(
603
+ const a = useSyncExternalStoreWithSelector(
604
store.subscribe,
605
store.getState,
606
null,
637
const store = createExternalStore({a: 0, b: 0});
638
639
function A() {
635
- const {a} = useSyncExternalStoreExtra(
640
+ const {a} = useSyncExternalStoreWithSelector(
641
store.subscribe,
642
store.getState,
643
null,
647
return <Text text={'A' + a} />;
648
}
649
function B() {
645
- const {b} = useSyncExternalStoreExtra(
650
+ const {b} = useSyncExternalStoreWithSelector(
651
store.subscribe,
652
store.getState,
653
null,
716
container.innerHTML = '<div>server</div>';
717
const serverRenderedDiv = container.getElementsByTagName('div')[0];
718
714
- if (gate(flags => flags.supportsNativeUseSyncExternalStore)) {
719
+ if (gate(flags => !flags.enableUseSyncExternalStoreShim)) {
720
act(() => {
721
ReactDOM.hydrateRoot(container, <App />);
722
});
779
Scheduler.unstable_yieldValue('Inline selector');
780
return [...state.items, 'C'];
781
};
777
- const items = useSyncExternalStoreExtra(
782
+ const items = useSyncExternalStoreWithSelector(
783
store.subscribe,
784
store.getState,
785
null,
847
const selector = state => state.a.toUpperCase();
848
849
function App() {
845
- const a = useSyncExternalStoreExtra(
850
+ const a = useSyncExternalStoreWithSelector(
851
store.subscribe,
852
store.getState,
853
null,
882
const isEqual = (left, right) => left.a.trim() === right.a.trim();
883
884
function App() {
880
- const a = useSyncExternalStoreExtra(
885
+ const a = useSyncExternalStoreWithSelector(
886
store.subscribe,
887
store.getState,
888
null,