@samitouri / QOS-React / commits / 69c7246d9d

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