Add "unstable_" prefix to experimental mutable source APIs (#19472)
* Add "unstbale_" prefix to mutable source APIs * DebugHooks no longer calls useMutableSource() on init This was causing an observable behavioral difference between experimental DEV and PROD builds. We don't initialize stack position for other composite hooks (e.g. useDeferredValue, useTransition, useOpaqueIdentifier). If we did, it would cause the same obesrvable behavioral difference.
Brian Vaughn committed
Jul 28, 2020 at 12:38 UTC
5227a37868c4bf3133ba5f2b3b39cac9175d7ea9
8 files changed
+76
-63
packages/react-debug-tools/src/ReactDebugHooks.js
-10
@@ -86,16 +86,6 @@ function getPrimitiveStackCache(): Map<string, Array<any>> {
86
Dispatcher.useDebugValue(null);
87
Dispatcher.useCallback(() => {});
88
Dispatcher.useMemo(() => null);
89
- Dispatcher.useMutableSource(
90
- {
91
- _source: {},
92
- _getVersion: () => 1,
93
- _workInProgressVersionPrimary: null,
94
- _workInProgressVersionSecondary: null,
95
- },
96
- () => null,
97
- () => () => {},
98
- );
89
} finally {
90
readHookLog = hookLog;
91
hookLog = [];
packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
+2
-2
@@ -848,9 +848,9 @@ describe('ReactHooksInspectionIntegration', () => {
848
849
if (__EXPERIMENTAL__) {
850
it('should support composite useMutableSource hook', () => {
851
- const mutableSource = React.createMutableSource({}, () => 1);
851
+ const mutableSource = React.unstable_createMutableSource({}, () => 1);
852
function Foo(props) {
853
- React.useMutableSource(
853
+ React.unstable_useMutableSource(
854
mutableSource,
855
() => 'snapshot',
856
() => {},
packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js
+58
-39
@@ -16,8 +16,9 @@ let React;
16
let ReactFeatureFlags;
17
let ReactNoop;
18
let Scheduler;
19
-let useMutableSource;
19
let act;
20
+let createMutableSource;
21
+let useMutableSource;
22
23
function loadModules() {
24
jest.resetModules();
@@ -30,8 +31,9 @@ function loadModules() {
31
React = require('react');
32
ReactNoop = require('react-noop-renderer');
33
Scheduler = require('scheduler');
33
- useMutableSource = React.useMutableSource;
34
act = ReactNoop.act;
35
+ createMutableSource = React.unstable_createMutableSource;
36
+ useMutableSource = React.unstable_useMutableSource;
37
}
38
39
describe('useMutableSource', () => {
@@ -129,10 +131,6 @@ describe('useMutableSource', () => {
131
};
132
}
133
132
- function createMutableSource(source) {
133
- return React.createMutableSource(source, param => param.version);
134
- }
135
-
134
function Component({getSnapshot, label, mutableSource, subscribe}) {
135
const snapshot = useMutableSource(mutableSource, getSnapshot, subscribe);
136
Scheduler.unstable_yieldValue(`${label}:${snapshot}`);
@@ -144,7 +142,7 @@ describe('useMutableSource', () => {
142
// @gate experimental
143
it('should subscribe to a source and schedule updates when it changes', () => {
144
const source = createSource('one');
147
- const mutableSource = createMutableSource(source);
145
+ const mutableSource = createMutableSource(source, param => param.version);
146
147
act(() => {
148
ReactNoop.renderToRootWithID(
@@ -212,7 +210,7 @@ describe('useMutableSource', () => {
210
// @gate experimental
211
it('should restart work if a new source is mutated during render', () => {
212
const source = createSource('one');
215
- const mutableSource = createMutableSource(source);
213
+ const mutableSource = createMutableSource(source, param => param.version);
214
215
act(() => {
216
ReactNoop.render(
@@ -247,7 +245,7 @@ describe('useMutableSource', () => {
245
// @gate experimental
246
it('should schedule an update if a new source is mutated between render and commit (subscription)', () => {
247
const source = createSource('one');
250
- const mutableSource = createMutableSource(source);
248
+ const mutableSource = createMutableSource(source, param => param.version);
249
250
act(() => {
251
ReactNoop.render(
@@ -287,10 +285,16 @@ describe('useMutableSource', () => {
285
// @gate experimental
286
it('should unsubscribe and resubscribe if a new source is used', () => {
287
const sourceA = createSource('a-one');
290
- const mutableSourceA = createMutableSource(sourceA);
288
+ const mutableSourceA = createMutableSource(
289
+ sourceA,
290
+ param => param.versionA,
291
+ );
292
293
const sourceB = createSource('b-one');
293
- const mutableSourceB = createMutableSource(sourceB);
294
+ const mutableSourceB = createMutableSource(
295
+ sourceB,
296
+ param => param.versionB,
297
+ );
298
299
act(() => {
300
ReactNoop.render(
@@ -338,7 +342,7 @@ describe('useMutableSource', () => {
342
// @gate experimental
343
it('should unsubscribe and resubscribe if a new subscribe function is provided', () => {
344
const source = createSource('a-one');
341
- const mutableSource = createMutableSource(source);
345
+ const mutableSource = createMutableSource(source, param => param.version);
346
347
const unsubscribeA = jest.fn();
348
const subscribeA = jest.fn(s => {
@@ -403,7 +407,7 @@ describe('useMutableSource', () => {
407
// @gate experimental
408
it('should re-use previously read snapshot value when reading is unsafe', () => {
409
const source = createSource('one');
406
- const mutableSource = createMutableSource(source);
410
+ const mutableSource = createMutableSource(source, param => param.version);
411
412
act(() => {
413
ReactNoop.render(
@@ -460,7 +464,7 @@ describe('useMutableSource', () => {
464
// @gate experimental
465
it('should read from source on newly mounted subtree if no pending updates are scheduled for source', () => {
466
const source = createSource('one');
463
- const mutableSource = createMutableSource(source);
467
+ const mutableSource = createMutableSource(source, param => param.version);
468
469
act(() => {
470
ReactNoop.render(
@@ -500,7 +504,7 @@ describe('useMutableSource', () => {
504
// @gate experimental
505
it('should throw and restart render if source and snapshot are unavailable during an update', () => {
506
const source = createSource('one');
503
- const mutableSource = createMutableSource(source);
507
+ const mutableSource = createMutableSource(source, param => param.version);
508
509
act(() => {
510
ReactNoop.render(
@@ -567,7 +571,7 @@ describe('useMutableSource', () => {
571
// @gate experimental
572
it('should throw and restart render if source and snapshot are unavailable during a sync update', () => {
573
const source = createSource('one');
570
- const mutableSource = createMutableSource(source);
574
+ const mutableSource = createMutableSource(source, param => param.version);
575
576
act(() => {
577
ReactNoop.render(
@@ -631,7 +635,7 @@ describe('useMutableSource', () => {
635
// @gate experimental
636
it('should only update components whose subscriptions fire', () => {
637
const source = createComplexSource('a:one', 'b:one');
634
- const mutableSource = createMutableSource(source);
638
+ const mutableSource = createMutableSource(source, param => param.version);
639
640
// Subscribe to part of the store.
641
const getSnapshotA = s => s.valueA;
@@ -670,7 +674,7 @@ describe('useMutableSource', () => {
674
// @gate experimental
675
it('should detect tearing in part of the store not yet subscribed to', () => {
676
const source = createComplexSource('a:one', 'b:one');
673
- const mutableSource = createMutableSource(source);
677
+ const mutableSource = createMutableSource(source, param => param.version);
678
679
// Subscribe to part of the store.
680
const getSnapshotA = s => s.valueA;
@@ -737,7 +741,7 @@ describe('useMutableSource', () => {
741
const MockComponent = jest.fn(Component);
742
743
const source = createSource('one');
740
- const mutableSource = createMutableSource(source);
744
+ const mutableSource = createMutableSource(source, param => param.version);
745
746
act(() => {
747
ReactNoop.render(
@@ -762,7 +766,7 @@ describe('useMutableSource', () => {
766
// @gate experimental
767
it('should throw and restart if getSnapshot changes between scheduled update and re-render', () => {
768
const source = createSource('one');
765
- const mutableSource = createMutableSource(source);
769
+ const mutableSource = createMutableSource(source, param => param.version);
770
771
const newGetSnapshot = s => 'new:' + defaultGetSnapshot(s);
772
@@ -808,7 +812,7 @@ describe('useMutableSource', () => {
812
// @gate experimental
813
it('should recover from a mutation during yield when other work is scheduled', () => {
814
const source = createSource('one');
811
- const mutableSource = createMutableSource(source);
815
+ const mutableSource = createMutableSource(source, param => param.version);
816
817
act(() => {
818
// Start a render that uses the mutable source.
@@ -842,7 +846,7 @@ describe('useMutableSource', () => {
846
// @gate experimental
847
it('should not throw if the new getSnapshot returns the same snapshot value', () => {
848
const source = createSource('one');
845
- const mutableSource = createMutableSource(source);
849
+ const mutableSource = createMutableSource(source, param => param.version);
850
851
const onRenderA = jest.fn();
852
const onRenderB = jest.fn();
@@ -897,7 +901,7 @@ describe('useMutableSource', () => {
901
// @gate experimental
902
it('should not throw if getSnapshot changes but the source can be safely read from anyway', () => {
903
const source = createSource('one');
900
- const mutableSource = createMutableSource(source);
904
+ const mutableSource = createMutableSource(source, param => param.version);
905
906
const newGetSnapshot = s => 'new:' + defaultGetSnapshot(s);
907
@@ -942,7 +946,7 @@ describe('useMutableSource', () => {
946
{id: 2, name: 'Bar'},
947
],
948
});
945
- const mutableSource = createMutableSource(source);
949
+ const mutableSource = createMutableSource(source, param => param.version);
950
951
function FriendsList() {
952
const getSnapshot = React.useCallback(
@@ -1004,7 +1008,7 @@ describe('useMutableSource', () => {
1008
// @gate experimental
1009
it('should not warn about updates that fire between unmount and passive unsubscribe', () => {
1010
const source = createSource('one');
1007
- const mutableSource = createMutableSource(source);
1011
+ const mutableSource = createMutableSource(source, param => param.version);
1012
1013
function Wrapper() {
1014
React.useLayoutEffect(() => () => {
@@ -1044,7 +1048,7 @@ describe('useMutableSource', () => {
1048
a: 'initial',
1049
b: 'initial',
1050
});
1047
- const mutableSource = createMutableSource(source);
1051
+ const mutableSource = createMutableSource(source, param => param.version);
1052
1053
const getSnapshotA = () => source.value.a;
1054
const getSnapshotB = () => source.value.b;
@@ -1089,7 +1093,7 @@ describe('useMutableSource', () => {
1093
a: 'initial',
1094
b: 'initial',
1095
});
1092
- const mutableSource = createMutableSource(source);
1096
+ const mutableSource = createMutableSource(source, param => param.version);
1097
1098
const getSnapshotA = () => source.value.a;
1099
const getSnapshotB = () => source.value.b;
@@ -1144,8 +1148,14 @@ describe('useMutableSource', () => {
1148
it('should clear the update queue when source changes with pending lower priority updates', async () => {
1149
const sourceA = createSource('initial');
1150
const sourceB = createSource('initial');
1147
- const mutableSourceA = createMutableSource(sourceA);
1148
- const mutableSourceB = createMutableSource(sourceB);
1151
+ const mutableSourceA = createMutableSource(
1152
+ sourceA,
1153
+ param => param.versionA,
1154
+ );
1155
+ const mutableSourceB = createMutableSource(
1156
+ sourceB,
1157
+ param => param.versionB,
1158
+ );
1159
1160
function App({toggle}) {
1161
const state = useMutableSource(
@@ -1185,7 +1195,7 @@ describe('useMutableSource', () => {
1195
a: 'foo',
1196
b: 'bar',
1197
});
1188
- const mutableSource = createMutableSource(source);
1198
+ const mutableSource = createMutableSource(source, param => param.version);
1199
1200
const getSnapshotA = () => source.value.a;
1201
const getSnapshotB = () => source.value.b;
@@ -1275,7 +1285,7 @@ describe('useMutableSource', () => {
1285
a: 'foo',
1286
b: 'bar',
1287
});
1278
- const mutableSource = createMutableSource(source);
1288
+ const mutableSource = createMutableSource(source, param => param.version);
1289
1290
function mutateB(newB) {
1291
source.value = {
@@ -1334,7 +1344,7 @@ describe('useMutableSource', () => {
1344
a: 'a0',
1345
b: 'b0',
1346
});
1337
- const mutableSource = createMutableSource(source);
1347
+ const mutableSource = createMutableSource(source, param => param.version);
1348
1349
const getSnapshotA = () => source.value.a;
1350
const getSnapshotB = () => source.value.b;
@@ -1408,7 +1418,7 @@ describe('useMutableSource', () => {
1418
a: 'a0',
1419
b: 'b0',
1420
});
1411
- const mutableSource = createMutableSource(source);
1421
+ const mutableSource = createMutableSource(source, param => param.version);
1422
1423
const getSnapshotA = () => source.value.a;
1424
const getSnapshotB = () => source.value.b;
@@ -1496,7 +1506,7 @@ describe('useMutableSource', () => {
1506
// @gate experimental
1507
it('warns about functions being used as snapshot values', async () => {
1508
const source = createSource(() => 'a');
1499
- const mutableSource = createMutableSource(source);
1509
+ const mutableSource = createMutableSource(source, param => param.version);
1510
1511
const getSnapshot = () => source.value;
1512
@@ -1526,7 +1536,7 @@ describe('useMutableSource', () => {
1536
const {useEffect} = React;
1537
1538
const source = createComplexSource('1', '2');
1529
- const mutableSource = createMutableSource(source);
1539
+ const mutableSource = createMutableSource(source, param => param.version);
1540
1541
// Subscribe to part of the store.
1542
const getSnapshotA = s => s.valueA;
@@ -1630,7 +1640,7 @@ describe('useMutableSource', () => {
1640
// @gate experimental
1641
it('should not tear with newly mounted component when updates were scheduled at a lower priority', async () => {
1642
const source = createSource('one');
1633
- const mutableSource = createMutableSource(source);
1643
+ const mutableSource = createMutableSource(source, param => param.version);
1644
1645
let committedA = null;
1646
let committedB = null;
@@ -1713,7 +1723,10 @@ describe('useMutableSource', () => {
1723
// @gate experimental
1724
it('should warn if the subscribe function does not return an unsubscribe function', () => {
1725
const source = createSource('one');
1716
- const mutableSource = createMutableSource(source);
1726
+ const mutableSource = createMutableSource(
1727
+ source,
1728
+ param => param.version,
1729
+ );
1730
1731
const brokenSubscribe = () => {};
1732
@@ -1736,7 +1749,10 @@ describe('useMutableSource', () => {
1749
// @gate experimental
1750
it('should error if multiple renderers of the same type use a mutable source at the same time', () => {
1751
const source = createSource('one');
1739
- const mutableSource = createMutableSource(source);
1752
+ const mutableSource = createMutableSource(
1753
+ source,
1754
+ param => param.version,
1755
+ );
1756
1757
act(() => {
1758
// Start a render that uses the mutable source.
@@ -1793,7 +1809,10 @@ describe('useMutableSource', () => {
1809
// @gate experimental
1810
it('should error if multiple renderers of the same type use a mutable source at the same time with mutation between', () => {
1811
const source = createSource('one');
1796
- const mutableSource = createMutableSource(source);
1812
+ const mutableSource = createMutableSource(
1813
+ source,
1814
+ param => param.version,
1815
+ );
1816
1817
act(() => {
1818
// Start a render that uses the mutable source.
packages/react-reconciler/src/__tests__/useMutableSourceHydration-test.js
+8
-10
@@ -14,6 +14,7 @@ let ReactDOM;
14
let ReactDOMServer;
15
let Scheduler;
16
let act;
17
+let createMutableSource;
18
let useMutableSource;
19
20
describe('useMutableSourceHydration', () => {
@@ -25,8 +26,9 @@ describe('useMutableSourceHydration', () => {
26
ReactDOMServer = require('react-dom/server');
27
Scheduler = require('scheduler');
28
28
- useMutableSource = React.useMutableSource;
29
act = require('react-dom/test-utils').act;
30
+ createMutableSource = React.unstable_createMutableSource;
31
+ useMutableSource = React.unstable_useMutableSource;
32
});
33
34
const defaultGetSnapshot = source => source.value;
@@ -123,10 +125,6 @@ describe('useMutableSourceHydration', () => {
125
};
126
}
127
126
- function createMutableSource(source) {
127
- return React.createMutableSource(source, param => param.version);
128
- }
129
-
128
function Component({getSnapshot, label, mutableSource, subscribe}) {
129
const snapshot = useMutableSource(mutableSource, getSnapshot, subscribe);
130
Scheduler.unstable_yieldValue(`${label}:${snapshot}`);
@@ -136,7 +134,7 @@ describe('useMutableSourceHydration', () => {
134
// @gate experimental
135
it('should render and hydrate', () => {
136
const source = createSource('one');
139
- const mutableSource = createMutableSource(source);
137
+ const mutableSource = createMutableSource(source, param => param.version);
138
139
function TestComponent() {
140
return (
@@ -173,7 +171,7 @@ describe('useMutableSourceHydration', () => {
171
// @gate experimental
172
it('should detect a tear before hydrating a component', () => {
173
const source = createSource('one');
176
- const mutableSource = createMutableSource(source);
174
+ const mutableSource = createMutableSource(source, param => param.version);
175
176
function TestComponent() {
177
return (
@@ -217,7 +215,7 @@ describe('useMutableSourceHydration', () => {
215
// @gate experimental
216
it('should detect a tear between hydrating components', () => {
217
const source = createSource('one');
220
- const mutableSource = createMutableSource(source);
218
+ const mutableSource = createMutableSource(source, param => param.version);
219
220
function TestComponent() {
221
return (
@@ -269,7 +267,7 @@ describe('useMutableSourceHydration', () => {
267
// @gate experimental
268
it('should detect a tear between hydrating components reading from different parts of a source', () => {
269
const source = createComplexSource('a:one', 'b:one');
272
- const mutableSource = createMutableSource(source);
270
+ const mutableSource = createMutableSource(source, param => param.version);
271
272
// Subscribe to part of the store.
273
const getSnapshotA = s => s.valueA;
@@ -336,7 +334,7 @@ describe('useMutableSourceHydration', () => {
334
// @gate experimental
335
it('should detect a tear during a higher priority interruption', () => {
336
const source = createSource('one');
339
- const mutableSource = createMutableSource(source);
337
+ const mutableSource = createMutableSource(source, param => param.version);
338
339
function Unrelated({flag}) {
340
Scheduler.unstable_yieldValue(flag);
packages/react/index.classic.fb.js
+2
@@ -27,7 +27,9 @@ export {
27
useRef,
28
useState,
29
useMutableSource,
30
+ useMutableSource as unstable_useMutableSource,
31
createMutableSource,
32
+ createMutableSource as unstable_createMutableSource,
33
Fragment,
34
Profiler,
35
StrictMode,
packages/react/index.experimental.js
+2
-2
@@ -26,8 +26,8 @@ export {
26
useReducer,
27
useRef,
28
useState,
29
- useMutableSource,
30
- createMutableSource,
29
+ useMutableSource as unstable_useMutableSource,
30
+ createMutableSource as unstable_createMutableSource,
31
Fragment,
32
Profiler,
33
StrictMode,
packages/react/index.js
+2
@@ -56,7 +56,9 @@ export {
56
useRef,
57
useState,
58
useMutableSource,
59
+ useMutableSource as unstable_useMutableSource,
60
createMutableSource,
61
+ createMutableSource as unstable_createMutableSource,
62
Fragment,
63
Profiler,
64
unstable_DebugTracingMode,
packages/react/index.modern.fb.js
+2
@@ -24,7 +24,9 @@ export {
24
useLayoutEffect,
25
useMemo,
26
useMutableSource,
27
+ useMutableSource as unstable_useMutableSource,
28
createMutableSource,
29
+ createMutableSource as unstable_createMutableSource,
30
useReducer,
31
useRef,
32
useState,