Initialize useMemoCache with sentinel values (#25465)
* Flush out useMemoCache API * rename symbol * rename symbol.for string name * workaround symbol export not working in unit tests
Joseph Savona committed
Oct 14, 2022 at 15:00 UTC
69c7246d9dec4f5a235f3d8353811df3a80d24f5
6 files changed
+41
-8
packages/react-reconciler/src/ReactFiberHooks.new.js
+4
-2
@@ -46,6 +46,7 @@ import {
46
import {
47
REACT_CONTEXT_TYPE,
48
REACT_SERVER_CONTEXT_TYPE,
49
+ REACT_MEMO_CACHE_SENTINEL,
50
} from 'shared/ReactSymbols';
51
52
import {
@@ -845,8 +846,6 @@ function useMemoCache(size: number): Array<any> {
846
memoCache = updateQueue.memoCache;
847
}
848
// Otherwise clone from the current fiber
848
- // TODO: not sure how to access the current fiber here other than going through
849
- // currentlyRenderingFiber.alternate
849
if (memoCache == null) {
850
const current: Fiber | null = currentlyRenderingFiber.alternate;
851
if (current !== null) {
@@ -878,6 +877,9 @@ function useMemoCache(size: number): Array<any> {
877
let data = memoCache.data[memoCache.index];
878
if (data === undefined) {
879
data = memoCache.data[memoCache.index] = new Array(size);
880
+ for (let i = 0; i < size; i++) {
881
+ data[i] = REACT_MEMO_CACHE_SENTINEL;
882
+ }
883
} else if (data.length !== size) {
884
// TODO: consider warning or throwing here
885
if (__DEV__) {
packages/react-reconciler/src/ReactFiberHooks.old.js
+4
-2
@@ -46,6 +46,7 @@ import {
46
import {
47
REACT_CONTEXT_TYPE,
48
REACT_SERVER_CONTEXT_TYPE,
49
+ REACT_MEMO_CACHE_SENTINEL,
50
} from 'shared/ReactSymbols';
51
52
import {
@@ -845,8 +846,6 @@ function useMemoCache(size: number): Array<any> {
846
memoCache = updateQueue.memoCache;
847
}
848
// Otherwise clone from the current fiber
848
- // TODO: not sure how to access the current fiber here other than going through
849
- // currentlyRenderingFiber.alternate
849
if (memoCache == null) {
850
const current: Fiber | null = currentlyRenderingFiber.alternate;
851
if (current !== null) {
@@ -878,6 +877,9 @@ function useMemoCache(size: number): Array<any> {
877
let data = memoCache.data[memoCache.index];
878
if (data === undefined) {
879
data = memoCache.data[memoCache.index] = new Array(size);
880
+ for (let i = 0; i < size; i++) {
881
+ data[i] = REACT_MEMO_CACHE_SENTINEL;
882
+ }
883
} else if (data.length !== size) {
884
// TODO: consider warning or throwing here
885
if (__DEV__) {
packages/react-reconciler/src/__tests__/useMemoCache-test.js
+14
-1
@@ -1,8 +1,19 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @emails react-core
8
+ * @jest-environment node
9
+ */
10
+
11
let React;
12
let ReactNoop;
13
let act;
14
let useState;
15
let useMemoCache;
16
+let MemoCacheSentinel;
17
let ErrorBoundary;
18
19
describe('useMemoCache()', () => {
@@ -14,6 +25,7 @@ describe('useMemoCache()', () => {
25
act = require('jest-react').act;
26
useState = React.useState;
27
useMemoCache = React.unstable_useMemoCache;
28
+ MemoCacheSentinel = Symbol.for('react.memo_cache_sentinel');
29
30
class _ErrorBoundary extends React.Component {
31
constructor(props) {
@@ -46,7 +58,8 @@ describe('useMemoCache()', () => {
58
const cache = useMemoCache(1);
59
expect(Array.isArray(cache)).toBe(true);
60
expect(cache.length).toBe(1);
49
- expect(cache[0]).toBe(undefined);
61
+ expect(cache[0]).toBe(MemoCacheSentinel);
62
+
63
return 'Ok';
64
}
65
const root = ReactNoop.createRoot();
packages/react-server/src/ReactFizzHooks.js
+6
-1
@@ -46,6 +46,7 @@ import is from 'shared/objectIs';
46
import {
47
REACT_SERVER_CONTEXT_TYPE,
48
REACT_CONTEXT_TYPE,
49
+ REACT_MEMO_CACHE_SENTINEL,
50
} from 'shared/ReactSymbols';
51
52
type BasicStateAction<S> = (S => S) | S;
@@ -666,7 +667,11 @@ function useCacheRefresh(): <T>(?() => T, ?T) => void {
667
}
668
669
function useMemoCache(size: number): Array<any> {
669
- return new Array(size);
670
+ const data = new Array(size);
671
+ for (let i = 0; i < size; i++) {
672
+ data[i] = REACT_MEMO_CACHE_SENTINEL;
673
+ }
674
+ return data;
675
}
676
677
function noop(): void {}
packages/react-server/src/ReactFlightHooks.js
+9
-2
@@ -11,7 +11,10 @@ import type {Dispatcher} from 'react-reconciler/src/ReactInternalTypes';
11
import type {Request} from './ReactFlightServer';
12
import type {ReactServerContext, Thenable, Usable} from 'shared/ReactTypes';
13
import type {ThenableState} from './ReactFlightWakeable';
14
-import {REACT_SERVER_CONTEXT_TYPE} from 'shared/ReactSymbols';
14
+import {
15
+ REACT_SERVER_CONTEXT_TYPE,
16
+ REACT_MEMO_CACHE_SENTINEL,
17
+} from 'shared/ReactSymbols';
18
import {readContext as readContextImpl} from './ReactFlightNewContext';
19
import {enableUseHook} from 'shared/ReactFeatureFlags';
20
import {
@@ -90,7 +93,11 @@ export const HooksDispatcher: Dispatcher = {
93
return unsupportedRefresh;
94
},
95
useMemoCache(size: number): Array<any> {
93
- return new Array(size);
96
+ const data = new Array(size);
97
+ for (let i = 0; i < size; i++) {
98
+ data[i] = REACT_MEMO_CACHE_SENTINEL;
99
+ }
100
+ return data;
101
},
102
use: enableUseHook ? use : (unsupportedHook: any),
103
};
packages/shared/ReactSymbols.js
+4
@@ -45,6 +45,10 @@ export const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED: symbol = Symbol.for(
45
'react.default_value',
46
);
47
48
+export const REACT_MEMO_CACHE_SENTINEL: symbol = Symbol.for(
49
+ 'react.memo_cache_sentinel',
50
+);
51
+
52
const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
53
const FAUX_ITERATOR_SYMBOL = '@@iterator';
54