@samitouri / QOS-React-2 / commits / 5227a37868

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,