Compare commits

...

1 Commits

Author SHA1 Message Date
Noah Lemen
7e3fb8610a wip userland memo 2024-03-25 17:13:28 -04:00
26 changed files with 341 additions and 110 deletions

View File

@@ -175,6 +175,7 @@ describe('ReactDOMServerIntegration', () => {
return readContext(Context);
}
const Memo = React.memo(() => {
const [a,b] = React.useState();
return readContext(Context);
});
const FwdRef = React.forwardRef((props, ref) => {

View File

@@ -59,7 +59,9 @@ describe('ReactDeprecationWarnings', () => {
);
await expect(async () => await waitForAll([])).toErrorDev(
'Warning: FunctionalComponent: Support for defaultProps ' +
'will be removed from memo components in a future major ' +
`will be removed from ${gate(flags =>
flags.enableUserlandMemo ? 'function' : 'memo',
)} components in a future major ` +
'release. Use JavaScript default parameters instead.',
);
});

View File

@@ -160,8 +160,14 @@ describe('ReactIs', () => {
const Component = () => React.createElement('div');
const Memoized = React.memo(Component);
expect(ReactIs.isValidElementType(Memoized)).toBe(true);
expect(ReactIs.typeOf(<Memoized />)).toBe(ReactIs.Memo);
expect(ReactIs.isMemo(<Memoized />)).toBe(true);
expect(ReactIs.typeOf(<Memoized />)).toBe(
gate(flags =>
flags.enableUserlandMemo ? ReactIs.Element : ReactIs.Memo,
),
);
expect(ReactIs.isMemo(<Memoized />)).toBe(
gate(flags => !flags.enableUserlandMemo),
);
expect(ReactIs.isMemo(<Component />)).toBe(false);
});

View File

@@ -39,6 +39,7 @@ import {
enableFloat,
enableDO_NOT_USE_disableStrictPassiveEffect,
enableRenderableContext,
enableUserlandMemo,
} from 'shared/ReactFeatureFlags';
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
import {ConcurrentRoot} from './ReactRootTags';
@@ -257,7 +258,7 @@ export function resolveLazyComponentTag(Component: Function): WorkTag {
if ($$typeof === REACT_FORWARD_REF_TYPE) {
return ForwardRef;
}
if ($$typeof === REACT_MEMO_TYPE) {
if (!enableUserlandMemo && $$typeof === REACT_MEMO_TYPE) {
return MemoComponent;
}
}
@@ -607,14 +608,16 @@ export function createFiberFromTypeAndProps(
resolvedType = resolveForwardRefForHotReloading(resolvedType);
}
break getTag;
case REACT_MEMO_TYPE:
fiberTag = MemoComponent;
break getTag;
case REACT_LAZY_TYPE:
fiberTag = LazyComponent;
resolvedType = null;
break getTag;
}
if (!enableUserlandMemo && type.$$typeof === REACT_MEMO_TYPE) {
fiberTag = MemoComponent;
break getTag;
}
}
let info = '';
if (__DEV__) {

View File

@@ -111,6 +111,7 @@ import {
enablePostpone,
enableRenderableContext,
enableRefAsProp,
enableUserlandMemo,
} from 'shared/ReactFeatureFlags';
import isArray from 'shared/isArray';
import shallowEqual from 'shared/shallowEqual';
@@ -479,6 +480,10 @@ function updateMemoComponent(
nextProps: any,
renderLanes: Lanes,
): null | Fiber {
if (enableUserlandMemo) {
return null;
}
if (current === null) {
const type = Component.type;
if (
@@ -565,6 +570,10 @@ function updateSimpleMemoComponent(
nextProps: any,
renderLanes: Lanes,
): null | Fiber {
if (enableUserlandMemo) {
return null;
}
// TODO: current can be non-null here even if the component
// hasn't yet mounted. This happens when the inner render suspends.
// We'll need to figure out if this is fine or can cause issues.
@@ -1694,6 +1703,17 @@ function mountLazyComponent(
const resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component));
const resolvedProps = resolveDefaultProps(Component, props);
let child;
if (!enableUserlandMemo && resolvedTag === MemoComponent) {
return updateMemoComponent(
null,
workInProgress,
Component,
resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too
renderLanes,
);
}
switch (resolvedTag) {
case FunctionComponent: {
if (__DEV__) {
@@ -1738,16 +1758,6 @@ function mountLazyComponent(
);
return child;
}
case MemoComponent: {
child = updateMemoComponent(
null,
workInProgress,
Component,
resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too
renderLanes,
);
return child;
}
}
let hint = '';
if (__DEV__) {
@@ -4038,6 +4048,31 @@ function beginWork(
// move this assignment out of the common path and into each branch.
workInProgress.lanes = NoLanes;
if (!enableUserlandMemo) {
if (workInProgress.tag === MemoComponent) {
const type = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
// Resolve outer props first, then resolve inner props.
let resolvedProps = resolveDefaultProps(type, unresolvedProps);
resolvedProps = resolveDefaultProps(type.type, resolvedProps);
return updateMemoComponent(
current,
workInProgress,
type,
resolvedProps,
renderLanes,
);
} else if (workInProgress.tag === SimpleMemoComponent) {
return updateSimpleMemoComponent(
current,
workInProgress,
workInProgress.type,
workInProgress.pendingProps,
renderLanes,
);
}
}
switch (workInProgress.tag) {
case IndeterminateComponent: {
return mountIndeterminateComponent(
@@ -4131,29 +4166,6 @@ function beginWork(
return updateContextProvider(current, workInProgress, renderLanes);
case ContextConsumer:
return updateContextConsumer(current, workInProgress, renderLanes);
case MemoComponent: {
const type = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
// Resolve outer props first, then resolve inner props.
let resolvedProps = resolveDefaultProps(type, unresolvedProps);
resolvedProps = resolveDefaultProps(type.type, resolvedProps);
return updateMemoComponent(
current,
workInProgress,
type,
resolvedProps,
renderLanes,
);
}
case SimpleMemoComponent: {
return updateSimpleMemoComponent(
current,
workInProgress,
workInProgress.type,
workInProgress.pendingProps,
renderLanes,
);
}
case IncompleteClassComponent: {
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;

View File

@@ -14,7 +14,7 @@ import type {Fiber, FiberRoot} from './ReactInternalTypes';
import type {Instance} from './ReactFiberConfig';
import type {ReactNodeList} from 'shared/ReactTypes';
import {enableFloat} from 'shared/ReactFeatureFlags';
import {enableFloat, enableUserlandMemo} from 'shared/ReactFeatureFlags';
import {
flushSync,
scheduleUpdateOnFiber,
@@ -181,18 +181,20 @@ export function isCompatibleFamilyForHotReloading(
}
break;
}
case MemoComponent:
case SimpleMemoComponent: {
if ($$typeofNextType === REACT_MEMO_TYPE) {
// TODO: if it was but can no longer be simple,
// we shouldn't set this.
needsCompareFamilies = true;
} else if ($$typeofNextType === REACT_LAZY_TYPE) {
needsCompareFamilies = true;
}
break;
}
default:
if (
(!enableUserlandMemo && fiber.tag === MemoComponent) ||
fiber.tag === SimpleMemoComponent
) {
if ($$typeofNextType === REACT_MEMO_TYPE) {
// TODO: if it was but can no longer be simple,
// we shouldn't set this.
needsCompareFamilies = true;
} else if ($$typeofNextType === REACT_LAZY_TYPE) {
needsCompareFamilies = true;
}
break;
}
return false;
}

View File

@@ -809,7 +809,9 @@ describe('ReactLazy', () => {
]
: shouldWarnAboutMemoDefaultProps
? [
'Add: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
`Add: Support for defaultProps will be removed from ${gate(flags =>
flags.enableUserlandMemo ? 'function' : 'memo',
)} components in a future major release. Use JavaScript default parameters instead.`,
]
: [],
);
@@ -1063,7 +1065,11 @@ describe('ReactLazy', () => {
await expect(async () => {
await act(() => resolveFakeImport(Add));
}).toErrorDev(
'Unknown: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
`${gate(flags =>
flags.enableUserlandMemo ? 'Memo' : 'Unknown',
)}: Support for defaultProps will be removed from ${gate(flags =>
flags.enableUserlandMemo ? 'function' : 'memo',
)} components in a future major release. Use JavaScript default parameters instead.`,
);
expect(root).toMatchRenderedOutput('4');
@@ -1149,10 +1155,18 @@ describe('ReactLazy', () => {
// Mount
await expect(async () => {
await act(() => resolveFakeImport(Add));
}).toErrorDev([
'Memo: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
'Unknown: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
]);
}).toErrorDev(
gate(flags =>
flags.enableUserlandMemo
? [
'Memo: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
]
: [
'Memo: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
'Unknown: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
],
),
);
expect(root).toMatchRenderedOutput('4');
// Update

View File

@@ -444,7 +444,9 @@ describe('memo', () => {
});
assertLog(['Loading...', 15]);
}).toErrorDev([
'Counter: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
`Counter: Support for defaultProps will be removed from ${gate(
flags => (flags.enableUserlandMemo ? 'function' : 'memo'),
)} components in a future major release. Use JavaScript default parameters instead.`,
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop={15} />);
@@ -503,7 +505,9 @@ describe('memo', () => {
);
});
}).toErrorDev([
'Support for defaultProps will be removed from memo component',
`Support for defaultProps will be removed from ${gate(flags =>
flags.enableUserlandMemo ? 'function' : 'memo',
)} component`,
]);
expect(root).toMatchRenderedOutput(<div>111</div>);
@@ -599,6 +603,9 @@ describe('memo', () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://react.dev/link/warning-keys for more information.\n' +
gate(flags =>
flags.enableUserlandMemo ? ' in elementType (at **)\n' : '',
) +
' in p (at **)',
);
});
@@ -617,6 +624,9 @@ describe('memo', () => {
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://react.dev/link/warning-keys for more information.\n' +
' in Inner (at **)\n' +
gate(flags =>
flags.enableUserlandMemo ? ' in elementType (at **)\n' : '',
) +
' in p (at **)',
);
});
@@ -637,6 +647,9 @@ describe('memo', () => {
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://react.dev/link/warning-keys for more information.\n' +
' in Inner (at **)\n' +
gate(flags =>
flags.enableUserlandMemo ? ' in elementType (at **)\n' : '',
) +
' in p (at **)',
);
});
@@ -656,6 +669,9 @@ describe('memo', () => {
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://react.dev/link/warning-keys for more information.\n' +
' in Outer (at **)\n' +
gate(flags =>
flags.enableUserlandMemo ? ' in elementType (at **)\n' : '',
) +
' in p (at **)',
);
});
@@ -677,6 +693,9 @@ describe('memo', () => {
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://react.dev/link/warning-keys for more information.\n' +
' in Inner (at **)\n' +
gate(flags =>
flags.enableUserlandMemo ? ' in elementType (at **)\n' : '',
) +
' in p (at **)',
);
});

View File

@@ -19,6 +19,8 @@ import type {
} from 'react-reconciler/src/ReactFiberHotReloading';
import type {ReactNodeList} from 'shared/ReactTypes';
import {enableUserlandMemo} from 'shared/ReactFeatureFlags';
import {REACT_MEMO_TYPE, REACT_FORWARD_REF_TYPE} from 'shared/ReactSymbols';
type Signature = {
@@ -330,13 +332,11 @@ export function register(type: any, id: string): void {
// Visit inner types because we might not have registered them.
if (typeof type === 'object' && type !== null) {
switch (getProperty(type, '$$typeof')) {
case REACT_FORWARD_REF_TYPE:
register(type.render, id + '$render');
break;
case REACT_MEMO_TYPE:
register(type.type, id + '$type');
break;
const property = getProperty(type, '$$typeof');
if (property === REACT_FORWARD_REF_TYPE) {
register(type.render, id + '$render');
} else if (!enableUserlandMemo && property === REACT_MEMO_TYPE) {
register(type.type, id + '$type');
}
}
} else {
@@ -363,13 +363,11 @@ export function setSignature(
}
// Visit inner types because we might not have signed them.
if (typeof type === 'object' && type !== null) {
switch (getProperty(type, '$$typeof')) {
case REACT_FORWARD_REF_TYPE:
setSignature(type.render, key, forceReset, getCustomHooks);
break;
case REACT_MEMO_TYPE:
setSignature(type.type, key, forceReset, getCustomHooks);
break;
const property = getProperty(type, '$$typeof');
if (property === REACT_FORWARD_REF_TYPE) {
setSignature(type.render, key, forceReset, getCustomHooks);
} else if (!enableUserlandMemo && property === REACT_MEMO_TYPE) {
setSignature(type.type, key, forceReset, getCustomHooks);
}
}
} else {
@@ -716,14 +714,11 @@ export function isLikelyComponentType(type: any): boolean {
}
case 'object': {
if (type != null) {
switch (getProperty(type, '$$typeof')) {
case REACT_FORWARD_REF_TYPE:
case REACT_MEMO_TYPE:
// Definitely React components.
return true;
default:
return false;
}
const property = getProperty(type, '$$typeof');
return (
property === REACT_FORWARD_REF_TYPE ||
(!enableUserlandMemo && property === REACT_MEMO_TYPE)
);
}
return false;
}

View File

@@ -146,6 +146,7 @@ import {
enablePostpone,
enableRenderableContext,
enableRefAsProp,
enableUserlandMemo,
} from 'shared/ReactFeatureFlags';
import assign from 'shared/assign';
@@ -1895,15 +1896,15 @@ function renderElement(
}
if (typeof type === 'object' && type !== null) {
if (!enableUserlandMemo && type.$$typeof === REACT_MEMO_TYPE) {
renderMemo(request, task, keyPath, type, props, ref);
return;
}
switch (type.$$typeof) {
case REACT_FORWARD_REF_TYPE: {
renderForwardRef(request, task, keyPath, type, props, ref);
return;
}
case REACT_MEMO_TYPE: {
renderMemo(request, task, keyPath, type, props, ref);
return;
}
case REACT_PROVIDER_TYPE: {
if (!enableRenderableContext) {
const context: ReactContext<any> = (type: any)._context;

View File

@@ -18,6 +18,7 @@ import {
enableServerComponentKeys,
enableRefAsProp,
enableServerComponentLogs,
enableUserlandMemo,
} from 'shared/ReactFeatureFlags';
import {
@@ -823,6 +824,9 @@ function renderElement(
// This is a reference to a Client Component.
return renderClientElement(task, type, key, props);
}
if (!enableUserlandMemo && type.$$typeof === REACT_MEMO_TYPE) {
return renderElement(request, task, type.type, key, ref, props);
}
switch (type.$$typeof) {
case REACT_LAZY_TYPE: {
const payload = type._payload;
@@ -833,9 +837,6 @@ function renderElement(
case REACT_FORWARD_REF_TYPE: {
return renderFunctionComponent(request, task, key, type.render, props);
}
case REACT_MEMO_TYPE: {
return renderElement(request, task, type.type, key, ref, props);
}
}
}
throw new Error(

View File

@@ -9,11 +9,17 @@
import {REACT_FORWARD_REF_TYPE, REACT_MEMO_TYPE} from 'shared/ReactSymbols';
import {enableUserlandMemo} from 'shared/ReactFeatureFlags';
export function forwardRef<Props, ElementType: React$ElementType>(
render: (props: Props, ref: React$Ref<ElementType>) => React$Node,
) {
if (__DEV__) {
if (render != null && render.$$typeof === REACT_MEMO_TYPE) {
if (
!enableUserlandMemo &&
render != null &&
render.$$typeof === REACT_MEMO_TYPE
) {
console.error(
'forwardRef requires a render function but received a `memo` ' +
'component. Instead of forwardRef(memo(...)), use ' +

View File

@@ -7,9 +7,92 @@
* @noflow
*/
import {REACT_MEMO_TYPE} from 'shared/ReactSymbols';
import type {Dispatcher} from './ReactInternalTypes';
import {
enableUserlandMemo,
enableRefAsProp,
enableCache,
enableUseMemoCacheHook,
enableUseEffectEventHook,
enableFormActions,
enableAsyncActions,
} from 'shared/ReactFeatureFlags';
import {REACT_ELEMENT_TYPE, REACT_MEMO_TYPE} from 'shared/ReactSymbols';
import {useState} from './ReactHooks';
import shallowEqual from 'shared/shallowEqual';
import assign from 'shared/assign';
import isValidElementType from 'shared/isValidElementType';
import ReactCurrentDispatcher from './ReactCurrentDispatcher';
// this currently seems to be duplicated all over the codebase. should it be moved to a shared implementation?
function resolveDefaultProps(Component: any, baseProps: Object): Object {
if (Component && Component.defaultProps) {
// Resolve default props. Taken from ReactElement
const props = assign({}, baseProps);
const defaultProps = Component.defaultProps;
for (const propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
return props;
}
return baseProps;
}
function throwInvalidHookError() {
throw new Error(
'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
' one of the following reasons:\n' +
'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
'2. You might be breaking the Rules of Hooks\n' +
'3. You might have more than one copy of React in the same app\n' +
'See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.',
);
}
export const MemoCompareDispatcher: Dispatcher = {
readContext: throwInvalidHookError,
use: throwInvalidHookError,
useCallback: throwInvalidHookError,
useContext: throwInvalidHookError,
useEffect: throwInvalidHookError,
useImperativeHandle: throwInvalidHookError,
useInsertionEffect: throwInvalidHookError,
useLayoutEffect: throwInvalidHookError,
useMemo: throwInvalidHookError,
useReducer: throwInvalidHookError,
useRef: throwInvalidHookError,
useState: throwInvalidHookError,
useDebugValue: throwInvalidHookError,
useDeferredValue: throwInvalidHookError,
useTransition: throwInvalidHookError,
useSyncExternalStore: throwInvalidHookError,
useId: throwInvalidHookError,
};
if (enableCache) {
(MemoCompareDispatcher: Dispatcher).useCacheRefresh = throwInvalidHookError;
}
if (enableUseMemoCacheHook) {
(MemoCompareDispatcher: Dispatcher).useMemoCache = throwInvalidHookError;
}
if (enableUseEffectEventHook) {
(MemoCompareDispatcher: Dispatcher).useEffectEvent = throwInvalidHookError;
}
if (enableFormActions && enableAsyncActions) {
(MemoCompareDispatcher: Dispatcher).useHostTransitionStatus =
throwInvalidHookError;
(MemoCompareDispatcher: Dispatcher).useFormState = throwInvalidHookError;
}
if (enableAsyncActions) {
(MemoCompareDispatcher: Dispatcher).useOptimistic = throwInvalidHookError;
}
export function memo<Props>(
type: React$ElementType,
@@ -24,18 +107,78 @@ export function memo<Props>(
);
}
}
const elementType = {
$$typeof: REACT_MEMO_TYPE,
type,
compare: compare === undefined ? null : compare,
};
let elementType;
if (enableUserlandMemo) {
elementType = props => {
const resolvedProps = resolveDefaultProps(type, props);
const [render, setRender] = useState(() => ({
$$typeof: REACT_ELEMENT_TYPE,
type,
props: resolvedProps,
}));
if (resolvedProps !== render.props) {
let previousDispatcher;
if (__DEV__) {
// previousDispatcher = ReactCurrentDispatcher.current;
// ReactCurrentDispatcher.current = MemoCompareDispatcher;
}
let shouldUpdate;
try {
shouldUpdate =
!(compare == null ? shallowEqual : compare)(
render.props,
resolvedProps,
) ||
(enableRefAsProp && props.ref !== render.props.ref);
} finally {
if (__DEV__) {
// ReactCurrentDispatcher.current = previousDispatcher;
}
}
if (shouldUpdate) {
setRender({
$$typeof: REACT_ELEMENT_TYPE,
type,
props: resolvedProps,
});
}
}
return render;
};
if (__DEV__) {
Object.defineProperty(elementType, 'name', {
enumerable: false,
configurable: true,
get: function () {
return null;
},
});
}
} else {
elementType = {
$$typeof: REACT_MEMO_TYPE,
type,
compare: compare === undefined ? null : compare,
};
}
if (__DEV__) {
let ownName;
Object.defineProperty(elementType, 'displayName', {
enumerable: false,
configurable: true,
get: function () {
return ownName;
if (enableUserlandMemo) {
return ownName || type.displayName || type.name || 'Memo';
} else {
return ownName;
}
},
set: function (name) {
ownName = name;

View File

@@ -402,6 +402,7 @@ describe('forwardRef', () => {
expect(differentRef.current.type).toBe('div');
});
// @gate !enableUserlandMemo
it('warns on forwardRef(memo(...))', () => {
expect(() => {
React.forwardRef(

View File

@@ -9,7 +9,10 @@
import type {LazyComponent} from 'react/src/ReactLazy';
import {enableComponentStackLocations} from 'shared/ReactFeatureFlags';
import {
enableComponentStackLocations,
enableUserlandMemo,
} from 'shared/ReactFeatureFlags';
import {
REACT_SUSPENSE_TYPE,
@@ -368,12 +371,13 @@ export function describeUnknownElementTypeFrameInDEV(
return describeBuiltInComponentFrame('SuspenseList', ownerFn);
}
if (typeof type === 'object') {
if (!enableUserlandMemo && type.$$typeof === REACT_MEMO_TYPE) {
// Memo may contain any component type so we recursively resolve it.
return describeUnknownElementTypeFrameInDEV(type.type, ownerFn);
}
switch (type.$$typeof) {
case REACT_FORWARD_REF_TYPE:
return describeFunctionComponentFrame(type.render, ownerFn);
case REACT_MEMO_TYPE:
// Memo may contain any component type so we recursively resolve it.
return describeUnknownElementTypeFrameInDEV(type.type, ownerFn);
case REACT_LAZY_TYPE: {
const lazyComponent: LazyComponent<any, any> = (type: any);
const payload = lazyComponent._payload;

View File

@@ -284,3 +284,5 @@ export const enableProfilerNestedUpdateScheduledHook = false;
export const consoleManagedByDevToolsDuringStrictMode = true;
export const enableDO_NOT_USE_disableStrictPassiveEffect = false;
export const enableUserlandMemo = false;

View File

@@ -20,6 +20,7 @@ import type {LazyComponent} from 'react/src/ReactLazy';
import isArray from 'shared/isArray';
import getPrototypeOf from 'shared/getPrototypeOf';
import {enableUserlandMemo} from './ReactFeatureFlags';
// Used for DEV messages to keep track of which parent rendered some props,
// in case they error.
@@ -131,11 +132,12 @@ function describeElementType(type: any): string {
return 'SuspenseList';
}
if (typeof type === 'object') {
if (!enableUserlandMemo && type.$$typeof === REACT_MEMO_TYPE) {
return describeElementType(type.type);
}
switch (type.$$typeof) {
case REACT_FORWARD_REF_TYPE:
return describeElementType(type.render);
case REACT_MEMO_TYPE:
return describeElementType(type.type);
case REACT_LAZY_TYPE: {
const lazyComponent: LazyComponent<any, any> = (type: any);
const payload = lazyComponent._payload;

View File

@@ -108,5 +108,7 @@ export const disableLegacyMode = false;
export const enableBigIntSupport = false;
export const enableUserlandMemo = false;
// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);

View File

@@ -99,5 +99,7 @@ export const enableReactTestRendererWarning = false;
export const enableBigIntSupport = false;
export const disableLegacyMode = false;
export const enableUserlandMemo = false;
// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);

View File

@@ -90,6 +90,8 @@ export const enableServerComponentKeys = true;
export const enableServerComponentLogs = true;
export const enableInfiniteRenderLoopDetection = false;
export const enableUserlandMemo = false;
// TODO: This must be in sync with the main ReactFeatureFlags file because
// the Test Renderer's value must be the same as the one used by the
// react package.

View File

@@ -95,5 +95,7 @@ export const disableLegacyMode = false;
export const enableBigIntSupport = false;
export const enableUserlandMemo = false;
// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);

View File

@@ -98,5 +98,7 @@ export const disableLegacyMode = false;
export const enableBigIntSupport = false;
export const enableUserlandMemo = false;
// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);

View File

@@ -35,6 +35,7 @@ export const enableRetryLaneExpiration = __VARIANT__;
export const retryLaneExpirationMs = 5000;
export const syncLaneExpirationMs = 250;
export const transitionLaneExpirationMs = 5000;
export const enableUserlandMemo = __VARIANT__;
// Enable this flag to help with concurrent mode debugging.
// It logs information to the console about React scheduling, rendering, and commit phases.

View File

@@ -39,6 +39,7 @@ export const {
useModernStrictMode,
enableRefAsProp,
enableClientRenderFallbackOnTextMismatch,
enableUserlandMemo,
} = dynamicFeatureFlags;
// On WWW, __EXPERIMENTAL__ is used for a new modern build.

View File

@@ -31,6 +31,7 @@ import {
enableTransitionTracing,
enableCache,
enableRenderableContext,
enableUserlandMemo,
} from './ReactFeatureFlags';
// Keep in sync with react-reconciler/getComponentNameFromFiber
@@ -102,6 +103,15 @@ export default function getComponentNameFromType(type: mixed): string | null {
);
}
}
if (!enableUserlandMemo && type.$$typeof === REACT_MEMO_TYPE) {
const outerName = (type: any).displayName || null;
if (outerName !== null) {
return outerName;
}
return getComponentNameFromType(type.type) || 'Memo';
}
switch (type.$$typeof) {
case REACT_PROVIDER_TYPE:
if (enableRenderableContext) {
@@ -126,12 +136,6 @@ export default function getComponentNameFromType(type: mixed): string | null {
}
case REACT_FORWARD_REF_TYPE:
return getWrappedName(type, type.render, 'ForwardRef');
case REACT_MEMO_TYPE:
const outerName = (type: any).displayName || null;
if (outerName !== null) {
return outerName;
}
return getComponentNameFromType(type.type) || 'Memo';
case REACT_LAZY_TYPE: {
const lazyComponent: LazyComponent<any, any> = (type: any);
const payload = lazyComponent._payload;

View File

@@ -33,6 +33,7 @@ import {
enableDebugTracing,
enableLegacyHidden,
enableRenderableContext,
enableUserlandMemo,
} from './ReactFeatureFlags';
const REACT_CLIENT_REFERENCE: symbol = Symbol.for('react.client.reference');
@@ -62,7 +63,7 @@ export default function isValidElementType(type: mixed): boolean {
if (typeof type === 'object' && type !== null) {
if (
type.$$typeof === REACT_LAZY_TYPE ||
type.$$typeof === REACT_MEMO_TYPE ||
(!enableUserlandMemo && type.$$typeof === REACT_MEMO_TYPE) ||
type.$$typeof === REACT_CONTEXT_TYPE ||
(!enableRenderableContext && type.$$typeof === REACT_PROVIDER_TYPE) ||
(enableRenderableContext && type.$$typeof === REACT_CONSUMER_TYPE) ||