[flags] remove enableOwnerStacks (#32426)

Bassed off: https://github.com/facebook/react/pull/32425

Wait to land internally.

[Commit to
review.](66aa6a4dbb)

This has landed everywhere
This commit is contained in:
Ricky 2025-03-04 12:34:34 -05:00 committed by GitHub
parent d48c69246c
commit e0fe347967
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
90 changed files with 1361 additions and 3191 deletions

View File

@ -857,17 +857,6 @@ describe('ReactInternalTestUtils console assertions', () => {
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);
} else if (gate(flags => flags.enableOwnerStacks)) {
expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected)
console.log was called without assertConsoleLogDev:
+ Not asserted
+ Not asserted
+ Not asserted
You must call one of the assertConsoleDev helpers between each act call."
`);
} else { } else {
expect(message).toMatchInlineSnapshot(` expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected) "asserConsoleLogsCleared(expected)
@ -937,20 +926,6 @@ describe('ReactInternalTestUtils console assertions', () => {
+ B + B
+ C + C
You must call one of the assertConsoleDev helpers between each act call."
`);
} else if (gate(flags => flags.enableOwnerStacks)) {
expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected)
console.warn was called without assertConsoleWarnDev:
+ A%s,
+ in App (at **)
+ B%s,
+ in App (at **)
+ C%s,
+ in App (at **)
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);
} else { } else {
@ -959,16 +934,10 @@ describe('ReactInternalTestUtils console assertions', () => {
console.warn was called without assertConsoleWarnDev: console.warn was called without assertConsoleWarnDev:
+ A%s, + A%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **) + in App (at **)
+ B%s, + B%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **) + in App (at **)
+ C%s, + C%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **) + in App (at **)
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
@ -1023,33 +992,6 @@ describe('ReactInternalTestUtils console assertions', () => {
+ B + B
+ C + C
You must call one of the assertConsoleDev helpers between each act call."
`);
} else if (gate(flags => flags.enableOwnerStacks)) {
expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected)
console.log was called without assertConsoleLogDev:
+ A
+ B
+ C
console.warn was called without assertConsoleWarnDev:
+ A%s,
+ in App (at **)
+ B%s,
+ in App (at **)
+ C%s,
+ in App (at **)
console.error was called without assertConsoleErrorDev:
+ A%s,
+ in App (at **)
+ B%s,
+ in App (at **)
+ C%s,
+ in App (at **)
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);
} else { } else {
@ -1063,30 +1005,18 @@ describe('ReactInternalTestUtils console assertions', () => {
console.warn was called without assertConsoleWarnDev: console.warn was called without assertConsoleWarnDev:
+ A%s, + A%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **) + in App (at **)
+ B%s, + B%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **) + in App (at **)
+ C%s, + C%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **) + in App (at **)
console.error was called without assertConsoleErrorDev: console.error was called without assertConsoleErrorDev:
+ A%s, + A%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **) + in App (at **)
+ B%s, + B%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **) + in App (at **)
+ C%s, + C%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **) + in App (at **)
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
@ -1927,20 +1857,6 @@ describe('ReactInternalTestUtils console assertions', () => {
+ Not asserted + Not asserted
+ Not asserted + Not asserted
You must call one of the assertConsoleDev helpers between each act call."
`);
} else if (gate(flags => flags.enableOwnerStacks)) {
expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected)
console.warn was called without assertConsoleWarnDev:
+ Not asserted%s,
+ in Yield (at **)
+ Not asserted%s,
+ in Yield (at **)
+ Not asserted%s,
+ in Yield (at **)
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);
} else { } else {
@ -1950,13 +1866,10 @@ describe('ReactInternalTestUtils console assertions', () => {
console.warn was called without assertConsoleWarnDev: console.warn was called without assertConsoleWarnDev:
+ Not asserted%s, + Not asserted%s,
+ in Yield (at **) + in Yield (at **)
+ in div (at **)
+ Not asserted%s, + Not asserted%s,
+ in Yield (at **) + in Yield (at **)
+ in div (at **)
+ Not asserted%s, + Not asserted%s,
+ in Yield (at **) + in Yield (at **)
+ in div (at **)
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);
@ -2020,7 +1933,7 @@ describe('ReactInternalTestUtils console assertions', () => {
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);
} else if (gate(flags => flags.enableOwnerStacks)) { } else {
expect(message).toMatchInlineSnapshot(` expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected) "asserConsoleLogsCleared(expected)
@ -2034,26 +1947,6 @@ describe('ReactInternalTestUtils console assertions', () => {
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);
} else {
expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected)
console.error was called without assertConsoleErrorDev:
+ A%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **)
+ B%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **)
+ C%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **)
You must call one of the assertConsoleDev helpers between each act call."
`);
} }
}); });
@ -2106,7 +1999,7 @@ describe('ReactInternalTestUtils console assertions', () => {
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);
} else if (gate(flags => flags.enableOwnerStacks)) { } else {
expect(message).toMatchInlineSnapshot(` expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected) "asserConsoleLogsCleared(expected)
@ -2133,45 +2026,6 @@ describe('ReactInternalTestUtils console assertions', () => {
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);
} else {
expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected)
console.log was called without assertConsoleLogDev:
+ A
+ B
+ C
console.warn was called without assertConsoleWarnDev:
+ A%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **)
+ B%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **)
+ C%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **)
console.error was called without assertConsoleErrorDev:
+ A%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **)
+ B%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **)
+ C%s,
+ in Yield (at **)
+ in div (at **)
+ in App (at **)
You must call one of the assertConsoleDev helpers between each act call."
`);
} }
}); });
@ -3052,20 +2906,6 @@ describe('ReactInternalTestUtils console assertions', () => {
+ Not asserted + Not asserted
+ Not asserted + Not asserted
You must call one of the assertConsoleDev helpers between each act call."
`);
} else if (gate(flags => flags.enableOwnerStacks)) {
expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected)
console.error was called without assertConsoleErrorDev:
+ Not asserted%s,
+ in Yield (at **)
+ Not asserted%s,
+ in Yield (at **)
+ Not asserted%s,
+ in Yield (at **)
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);
} else { } else {
@ -3075,13 +2915,10 @@ describe('ReactInternalTestUtils console assertions', () => {
console.error was called without assertConsoleErrorDev: console.error was called without assertConsoleErrorDev:
+ Not asserted%s, + Not asserted%s,
+ in Yield (at **) + in Yield (at **)
+ in div (at **)
+ Not asserted%s, + Not asserted%s,
+ in Yield (at **) + in Yield (at **)
+ in div (at **)
+ Not asserted%s, + Not asserted%s,
+ in Yield (at **) + in Yield (at **)
+ in div (at **)
You must call one of the assertConsoleDev helpers between each act call." You must call one of the assertConsoleDev helpers between each act call."
`); `);

View File

@ -6,6 +6,7 @@
*/ */
/* eslint-disable react-internal/no-production-logging */ /* eslint-disable react-internal/no-production-logging */
const chalk = require('chalk'); const chalk = require('chalk');
const util = require('util'); const util = require('util');
const shouldIgnoreConsoleError = require('./shouldIgnoreConsoleError'); const shouldIgnoreConsoleError = require('./shouldIgnoreConsoleError');
@ -38,25 +39,16 @@ const patchConsoleMethod = (methodName, logged) => {
(methodName === 'error' || methodName === 'warn') (methodName === 'error' || methodName === 'warn')
) { ) {
const React = require('react'); const React = require('react');
// Ideally we could remove this check, but we have some tests like
// useSyncExternalStoreShared-test that tests against React 17,
// which doesn't have the captureOwnerStack method.
if (React.captureOwnerStack) { if (React.captureOwnerStack) {
// enableOwnerStacks enabled. When it's always on, we can assume this case.
const stack = React.captureOwnerStack(); const stack = React.captureOwnerStack();
if (stack) { if (stack) {
format += '%s'; format += '%s';
args.push(stack); args.push(stack);
} }
} else {
// Otherwise we have to use internals to emulate parent stacks.
const ReactSharedInternals =
React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE ||
React.__SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
if (ReactSharedInternals && ReactSharedInternals.getCurrentStack) {
const stack = ReactSharedInternals.getCurrentStack();
if (stack !== '') {
format += '%s';
args.push(stack);
}
}
} }
} }

View File

@ -203,11 +203,7 @@ describe('ReactCache', () => {
"boolean, but instead received: [ 'Hi', 100 ]\n\n" + "boolean, but instead received: [ 'Hi', 100 ]\n\n" +
'To use non-primitive values as keys, you must pass a hash ' + 'To use non-primitive values as keys, you must pass a hash ' +
'function as the second argument to createResource().\n' + 'function as the second argument to createResource().\n' +
' in App (at **)' + ' in App (at **)',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in Suspense (at **)'),
...(gate('enableSiblingPrerendering') ...(gate('enableSiblingPrerendering')
? [ ? [
'Invalid key type. Expected a string, number, symbol, or ' + 'Invalid key type. Expected a string, number, symbol, or ' +

View File

@ -45,7 +45,6 @@ import type {TemporaryReferenceSet} from './ReactFlightTemporaryReferences';
import { import {
enablePostpone, enablePostpone,
enableOwnerStacks,
enableProfilerTimer, enableProfilerTimer,
enableComponentPerformanceTrack, enableComponentPerformanceTrack,
} from 'shared/ReactFeatureFlags'; } from 'shared/ReactFeatureFlags';
@ -755,7 +754,7 @@ function createElement(
configurable: false, configurable: false,
enumerable: false, enumerable: false,
writable: true, writable: true,
value: enableOwnerStacks ? validated : 1, // Whether the element has already been validated on the server. value: validated, // Whether the element has already been validated on the server.
}); });
// debugInfo contains Server Component debug information. // debugInfo contains Server Component debug information.
Object.defineProperty(element, '_debugInfo', { Object.defineProperty(element, '_debugInfo', {
@ -765,79 +764,68 @@ function createElement(
value: null, value: null,
}); });
let env = response._rootEnvironmentName; let env = response._rootEnvironmentName;
if (enableOwnerStacks) { if (owner !== null && owner.env != null) {
if (owner !== null && owner.env != null) { // Interestingly we don't actually have the environment name of where
// Interestingly we don't actually have the environment name of where // this JSX was created if it doesn't have an owner but if it does
// this JSX was created if it doesn't have an owner but if it does // it must be the same environment as the owner. We could send it separately
// it must be the same environment as the owner. We could send it separately // but it seems a bit unnecessary for this edge case.
// but it seems a bit unnecessary for this edge case. env = owner.env;
env = owner.env; }
} let normalizedStackTrace: null | Error = null;
let normalizedStackTrace: null | Error = null; if (owner === null && response._debugRootStack != null) {
if (owner === null && response._debugRootStack != null) { // We override the stack if we override the owner since the stack where the root JSX
// We override the stack if we override the owner since the stack where the root JSX // was created on the server isn't very useful but where the request was made is.
// was created on the server isn't very useful but where the request was made is. normalizedStackTrace = response._debugRootStack;
normalizedStackTrace = response._debugRootStack; } else if (stack !== null) {
} else if (stack !== null) { // We create a fake stack and then create an Error object inside of it.
// We create a fake stack and then create an Error object inside of it. // This means that the stack trace is now normalized into the native format
// This means that the stack trace is now normalized into the native format // of the browser and the stack frames will have been registered with
// of the browser and the stack frames will have been registered with // source mapping information.
// source mapping information. // This can unfortunately happen within a user space callstack which will
// This can unfortunately happen within a user space callstack which will // remain on the stack.
// remain on the stack. normalizedStackTrace = createFakeJSXCallStackInDEV(response, stack, env);
normalizedStackTrace = createFakeJSXCallStackInDEV( }
response, Object.defineProperty(element, '_debugStack', {
stack, configurable: false,
env, enumerable: false,
); writable: true,
} value: normalizedStackTrace,
Object.defineProperty(element, '_debugStack', { });
configurable: false,
enumerable: false,
writable: true,
value: normalizedStackTrace,
});
let task: null | ConsoleTask = null;
if (supportsCreateTask && stack !== null) {
const createTaskFn = (console: any).createTask.bind(
console,
getTaskName(type),
);
const callStack = buildFakeCallStack(
response,
stack,
env,
createTaskFn,
);
// This owner should ideally have already been initialized to avoid getting
// user stack frames on the stack.
const ownerTask =
owner === null ? null : initializeFakeTask(response, owner, env);
if (ownerTask === null) {
const rootTask = response._debugRootTask;
if (rootTask != null) {
task = rootTask.run(callStack);
} else {
task = callStack();
}
} else {
task = ownerTask.run(callStack);
}
}
Object.defineProperty(element, '_debugTask', {
configurable: false,
enumerable: false,
writable: true,
value: task,
});
let task: null | ConsoleTask = null;
if (supportsCreateTask && stack !== null) {
const createTaskFn = (console: any).createTask.bind(
console,
getTaskName(type),
);
const callStack = buildFakeCallStack(response, stack, env, createTaskFn);
// This owner should ideally have already been initialized to avoid getting // This owner should ideally have already been initialized to avoid getting
// user stack frames on the stack. // user stack frames on the stack.
if (owner !== null) { const ownerTask =
initializeFakeStack(response, owner); owner === null ? null : initializeFakeTask(response, owner, env);
if (ownerTask === null) {
const rootTask = response._debugRootTask;
if (rootTask != null) {
task = rootTask.run(callStack);
} else {
task = callStack();
}
} else {
task = ownerTask.run(callStack);
} }
} }
Object.defineProperty(element, '_debugTask', {
configurable: false,
enumerable: false,
writable: true,
value: task,
});
// This owner should ideally have already been initialized to avoid getting
// user stack frames on the stack.
if (owner !== null) {
initializeFakeStack(response, owner);
}
} }
if (initializingHandler !== null) { if (initializingHandler !== null) {
@ -863,13 +851,11 @@ function createElement(
name: getComponentNameFromType(element.type) || '', name: getComponentNameFromType(element.type) || '',
owner: element._owner, owner: element._owner,
}; };
if (enableOwnerStacks) { // $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write] // $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack; erroredComponent.debugTask = element._debugTask;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write]
erroredComponent.debugTask = element._debugTask;
}
} }
erroredChunk._debugInfo = [erroredComponent]; erroredChunk._debugInfo = [erroredComponent];
} }
@ -1057,13 +1043,11 @@ function waitForReference<T>(
name: getComponentNameFromType(element.type) || '', name: getComponentNameFromType(element.type) || '',
owner: element._owner, owner: element._owner,
}; };
if (enableOwnerStacks) { // $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write] // $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack; erroredComponent.debugTask = element._debugTask;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write]
erroredComponent.debugTask = element._debugTask;
}
} }
const chunkDebugInfo: ReactDebugInfo = const chunkDebugInfo: ReactDebugInfo =
chunk._debugInfo || (chunk._debugInfo = []); chunk._debugInfo || (chunk._debugInfo = []);
@ -1223,13 +1207,11 @@ function loadServerReference<A: Iterable<any>, T>(
name: getComponentNameFromType(element.type) || '', name: getComponentNameFromType(element.type) || '',
owner: element._owner, owner: element._owner,
}; };
if (enableOwnerStacks) { // $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write] // $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack; erroredComponent.debugTask = element._debugTask;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write]
erroredComponent.debugTask = element._debugTask;
}
} }
const chunkDebugInfo: ReactDebugInfo = const chunkDebugInfo: ReactDebugInfo =
chunk._debugInfo || (chunk._debugInfo = []); chunk._debugInfo || (chunk._debugInfo = []);
@ -1609,8 +1591,8 @@ function parseModelTuple(
tuple[2], tuple[2],
tuple[3], tuple[3],
__DEV__ ? (tuple: any)[4] : null, __DEV__ ? (tuple: any)[4] : null,
__DEV__ && enableOwnerStacks ? (tuple: any)[5] : null, __DEV__ ? (tuple: any)[5] : null,
__DEV__ && enableOwnerStacks ? (tuple: any)[6] : 0, __DEV__ ? (tuple: any)[6] : 0,
); );
} }
return value; return value;
@ -2083,27 +2065,6 @@ function stopStream(
controller.close(row === '' ? '"$undefined"' : row); controller.close(row === '' ? '"$undefined"' : row);
} }
function formatV8Stack(
errorName: string,
errorMessage: string,
stack: null | ReactStackTrace,
): string {
let v8StyleStack = errorName + ': ' + errorMessage;
if (stack) {
for (let i = 0; i < stack.length; i++) {
const frame = stack[i];
const [name, filename, line, col] = frame;
if (!name) {
v8StyleStack += '\n at ' + filename + ':' + line + ':' + col;
} else {
v8StyleStack +=
'\n at ' + name + ' (' + filename + ':' + line + ':' + col + ')';
}
}
}
return v8StyleStack;
}
type ErrorWithDigest = Error & {digest?: string}; type ErrorWithDigest = Error & {digest?: string};
function resolveErrorProd(response: Response): Error { function resolveErrorProd(response: Response): Error {
if (__DEV__) { if (__DEV__) {
@ -2202,34 +2163,20 @@ function resolvePostponeDev(
); );
} }
let postponeInstance: Postpone; let postponeInstance: Postpone;
if (!enableOwnerStacks) { const callStack = buildFakeCallStack(
// Executing Error within a native stack isn't really limited to owner stacks response,
// but we gate it behind the same flag for now while iterating. stack,
// eslint-disable-next-line react-internal/prod-error-codes env,
postponeInstance = (Error(reason || ''): any); // $FlowFixMe[incompatible-use]
postponeInstance.$$typeof = REACT_POSTPONE_TYPE; Error.bind(null, reason || ''),
// For backwards compat we use the V8 formatting when the flag is off. );
postponeInstance.stack = formatV8Stack( const rootTask = response._debugRootTask;
postponeInstance.name, if (rootTask != null) {
postponeInstance.message, postponeInstance = rootTask.run(callStack);
stack,
);
} else { } else {
const callStack = buildFakeCallStack( postponeInstance = callStack();
response,
stack,
env,
// $FlowFixMe[incompatible-use]
Error.bind(null, reason || ''),
);
const rootTask = response._debugRootTask;
if (rootTask != null) {
postponeInstance = rootTask.run(callStack);
} else {
postponeInstance = callStack();
}
postponeInstance.$$typeof = REACT_POSTPONE_TYPE;
} }
postponeInstance.$$typeof = REACT_POSTPONE_TYPE;
const chunks = response._chunks; const chunks = response._chunks;
const chunk = chunks.get(id); const chunk = chunks.get(id);
if (!chunk) { if (!chunk) {
@ -2248,8 +2195,7 @@ function resolveHint<Code: HintCode>(
dispatchHint(code, hintModel); dispatchHint(code, hintModel);
} }
const supportsCreateTask = const supportsCreateTask = __DEV__ && !!(console: any).createTask;
__DEV__ && enableOwnerStacks && !!(console: any).createTask;
type FakeFunction<T> = (() => T) => T; type FakeFunction<T> = (() => T) => T;
const fakeFunctionCache: Map<string, FakeFunction<any>> = __DEV__ const fakeFunctionCache: Map<string, FakeFunction<any>> = __DEV__
@ -2590,15 +2536,11 @@ function resolveDebugInfo(
let currentOwnerInDEV: null | ReactComponentInfo = null; let currentOwnerInDEV: null | ReactComponentInfo = null;
function getCurrentStackInDEV(): string { function getCurrentStackInDEV(): string {
if (__DEV__) { if (__DEV__) {
if (enableOwnerStacks) { const owner: null | ReactComponentInfo = currentOwnerInDEV;
const owner: null | ReactComponentInfo = currentOwnerInDEV; if (owner === null) {
if (owner === null) { return '';
return '';
}
return getOwnerStackByComponentInfoInDev(owner);
} }
// We don't have Parent Stacks in Flight. return getOwnerStackByComponentInfoInDev(owner);
return '';
} }
return ''; return '';
} }

View File

@ -321,9 +321,7 @@ describe('ReactFlight', () => {
env: 'Server', env: 'Server',
key: null, key: null,
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in Object.<anonymous> (at **)',
? ' in Object.<anonymous> (at **)'
: undefined,
props: { props: {
firstName: 'Seb', firstName: 'Seb',
lastName: 'Smith', lastName: 'Smith',
@ -367,9 +365,7 @@ describe('ReactFlight', () => {
env: 'Server', env: 'Server',
key: null, key: null,
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in Object.<anonymous> (at **)',
? ' in Object.<anonymous> (at **)'
: undefined,
props: { props: {
firstName: 'Seb', firstName: 'Seb',
lastName: 'Smith', lastName: 'Smith',
@ -1400,30 +1396,19 @@ describe('ReactFlight', () => {
environmentName: 'Server', environmentName: 'Server',
}, },
], ],
findSourceMapURLCalls: gate(flags => flags.enableOwnerStacks) findSourceMapURLCalls: [
? [ [__filename, 'Server'],
[__filename, 'Server'], [__filename, 'Server'],
[__filename, 'Server'], // TODO: What should we request here? The outer (<anonymous>) or the inner (inspected-page.html)?
// TODO: What should we request here? The outer (<anonymous>) or the inner (inspected-page.html)? ['inspected-page.html:29:11), <anonymous>', 'Server'],
['inspected-page.html:29:11), <anonymous>', 'Server'], [
[ 'file://~/(some)(really)(exotic-directory)/ReactFlight-test.js',
'file://~/(some)(really)(exotic-directory)/ReactFlight-test.js', 'Server',
'Server', ],
], ['file:///testing.js', 'Server'],
['file:///testing.js', 'Server'], ['', 'Server'],
['', 'Server'], [__filename, 'Server'],
[__filename, 'Server'], ],
]
: [
// TODO: What should we request here? The outer (<anonymous>) or the inner (inspected-page.html)?
['inspected-page.html:29:11), <anonymous>', 'Server'],
[
'file://~/(some)(really)(exotic-directory)/ReactFlight-test.js',
'Server',
],
['file:///testing.js', 'Server'],
['', 'Server'],
],
}); });
} else { } else {
expect(errors.map(getErrorForJestMatcher)).toEqual([ expect(errors.map(getErrorForJestMatcher)).toEqual([
@ -1475,9 +1460,6 @@ describe('ReactFlight', () => {
'Check the render method of `Component`. See https://react.dev/link/warning-keys for more information.\n' + 'Check the render method of `Component`. See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Component (at **)\n' + ' in Component (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Indirection (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
}); });
@ -1538,46 +1520,26 @@ describe('ReactFlight', () => {
}, },
}; };
const transport = ReactNoopFlightServer.render(<input value={obj} />); const transport = ReactNoopFlightServer.render(<input value={obj} />);
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev(
assertConsoleErrorDev( [
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' + 'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' + 'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' + ' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^\n' + ' ^^^^^^^^^^^^^^^',
' at (<anonymous>)', ],
]); {withoutStack: true},
} else { );
assertConsoleErrorDev(
[ ReactNoopFlightClient.read(transport);
'Only plain objects can be passed to Client Components from Server Components. ' + assertConsoleErrorDev([
'Objects with toJSON methods are not supported. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Convert it manually to a simple value before passing it to props.\n' + 'Objects with toJSON methods are not supported. ' +
' <input value={{toJSON: ...}}>\n' + 'Convert it manually to a simple value before passing it to props.\n' +
' ^^^^^^^^^^^^^^^', ' <input value={{toJSON: ...}}>\n' +
'Only plain objects can be passed to Client Components from Server Components. ' + ' ^^^^^^^^^^^^^^^\n' +
'Objects with toJSON methods are not supported. ' + ' at (<anonymous>)',
'Convert it manually to a simple value before passing it to props.\n' + ]);
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
}); });
it('should warn in DEV if a toJSON instance is passed to a host component child', () => { it('should warn in DEV if a toJSON instance is passed to a host component child', () => {
@ -1589,120 +1551,68 @@ describe('ReactFlight', () => {
const transport = ReactNoopFlightServer.render( const transport = ReactNoopFlightServer.render(
<div>Womp womp: {new MyError('spaghetti')}</div>, <div>Womp womp: {new MyError('spaghetti')}</div>,
); );
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev(
assertConsoleErrorDev( [
[
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' + 'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' + ' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^\n' + ' ^^^^^^^',
' at (<anonymous>)', ],
]); {withoutStack: true},
} else { );
assertConsoleErrorDev(
[ ReactNoopFlightClient.read(transport);
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' + assertConsoleErrorDev([
' <div>Womp womp: {Error}</div>\n' + 'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' ^^^^^^^', ' <div>Womp womp: {Error}</div>\n' +
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' + ' ^^^^^^^\n' +
' <div>Womp womp: {Error}</div>\n' + ' at (<anonymous>)',
' ^^^^^^^', ]);
],
{withoutStack: true},
);
}
}); });
it('should warn in DEV if a special object is passed to a host component', () => { it('should warn in DEV if a special object is passed to a host component', () => {
const transport = ReactNoopFlightServer.render(<input value={Math} />); const transport = ReactNoopFlightServer.render(<input value={Math} />);
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev(
assertConsoleErrorDev( [
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' + 'Math objects are not supported.\n' +
' <input value={Math}>\n' + ' <input value={Math}>\n' +
' ^^^^^^\n' + ' ^^^^^^',
' at (<anonymous>)', ],
]); {withoutStack: true},
} else { );
assertConsoleErrorDev(
[ ReactNoopFlightClient.read(transport);
'Only plain objects can be passed to Client Components from Server Components. ' + assertConsoleErrorDev([
'Math objects are not supported.\n' + 'Only plain objects can be passed to Client Components from Server Components. ' +
' <input value={Math}>\n' + 'Math objects are not supported.\n' +
' ^^^^^^', ' <input value={Math}>\n' +
'Only plain objects can be passed to Client Components from Server Components. ' + ' ^^^^^^\n' +
'Math objects are not supported.\n' + ' at (<anonymous>)',
' <input value={Math}>\n' + ]);
' ^^^^^^',
],
{withoutStack: true},
);
}
}); });
it('should warn in DEV if an object with symbols is passed to a host component', () => { it('should warn in DEV if an object with symbols is passed to a host component', () => {
const transport = ReactNoopFlightServer.render( const transport = ReactNoopFlightServer.render(
<input value={{[Symbol.iterator]: {}}} />, <input value={{[Symbol.iterator]: {}}} />,
); );
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev(
assertConsoleErrorDev( [
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' + ' <input value={{}}>\n' +
' ^^^^\n' + ' ^^^^',
' at (<anonymous>)', ],
]); {withoutStack: true},
} else { );
assertConsoleErrorDev(
[ ReactNoopFlightClient.read(transport);
'Only plain objects can be passed to Client Components from Server Components. ' + assertConsoleErrorDev([
'Objects with symbol properties like Symbol.iterator are not supported.\n' + 'Only plain objects can be passed to Client Components from Server Components. ' +
' <input value={{}}>\n' + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' ^^^^', ' <input value={{}}>\n' +
'Only plain objects can be passed to Client Components from Server Components. ' + ' ^^^^\n' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' + ' at (<anonymous>)',
' <input value={{}}>\n' + ]);
' ^^^^',
],
{withoutStack: true},
);
}
}); });
it('should warn in DEV if a toJSON instance is passed to a Client Component', () => { it('should warn in DEV if a toJSON instance is passed to a Client Component', () => {
@ -1716,46 +1626,26 @@ describe('ReactFlight', () => {
} }
const Client = clientReference(ClientImpl); const Client = clientReference(ClientImpl);
const transport = ReactNoopFlightServer.render(<Client value={obj} />); const transport = ReactNoopFlightServer.render(<Client value={obj} />);
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev(
assertConsoleErrorDev( [
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' + 'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' + 'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' + ' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^\n' + ' ^^^^^^^^^^^^^^^',
' at (<anonymous>)', ],
]); {withoutStack: true},
} else { );
assertConsoleErrorDev(
[ ReactNoopFlightClient.read(transport);
'Only plain objects can be passed to Client Components from Server Components. ' + assertConsoleErrorDev([
'Objects with toJSON methods are not supported. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Convert it manually to a simple value before passing it to props.\n' + 'Objects with toJSON methods are not supported. ' +
' <... value={{toJSON: ...}}>\n' + 'Convert it manually to a simple value before passing it to props.\n' +
' ^^^^^^^^^^^^^^^', ' <... value={{toJSON: ...}}>\n' +
'Only plain objects can be passed to Client Components from Server Components. ' + ' ^^^^^^^^^^^^^^^\n' +
'Objects with toJSON methods are not supported. ' + ' at (<anonymous>)',
'Convert it manually to a simple value before passing it to props.\n' + ]);
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
}); });
it('should warn in DEV if a toJSON instance is passed to a Client Component child', () => { it('should warn in DEV if a toJSON instance is passed to a Client Component child', () => {
@ -1771,46 +1661,26 @@ describe('ReactFlight', () => {
const transport = ReactNoopFlightServer.render( const transport = ReactNoopFlightServer.render(
<Client>Current date: {obj}</Client>, <Client>Current date: {obj}</Client>,
); );
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev(
assertConsoleErrorDev( [
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' + 'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' + 'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' + ' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^\n' + ' ^^^^^^^^^^^^^^^',
' at (<anonymous>)', ],
]); {withoutStack: true},
} else { );
assertConsoleErrorDev(
[ ReactNoopFlightClient.read(transport);
'Only plain objects can be passed to Client Components from Server Components. ' + assertConsoleErrorDev([
'Objects with toJSON methods are not supported. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Convert it manually to a simple value before passing it to props.\n' + 'Objects with toJSON methods are not supported. ' +
' <>Current date: {{toJSON: ...}}</>\n' + 'Convert it manually to a simple value before passing it to props.\n' +
' ^^^^^^^^^^^^^^^', ' <>Current date: {{toJSON: ...}}</>\n' +
'Only plain objects can be passed to Client Components from Server Components. ' + ' ^^^^^^^^^^^^^^^\n' +
'Objects with toJSON methods are not supported. ' + ' at (<anonymous>)',
'Convert it manually to a simple value before passing it to props.\n' + ]);
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
}); });
it('should warn in DEV if a special object is passed to a Client Component', () => { it('should warn in DEV if a special object is passed to a Client Component', () => {
@ -1819,43 +1689,24 @@ describe('ReactFlight', () => {
} }
const Client = clientReference(ClientImpl); const Client = clientReference(ClientImpl);
const transport = ReactNoopFlightServer.render(<Client value={Math} />); const transport = ReactNoopFlightServer.render(<Client value={Math} />);
assertConsoleErrorDev(
if (gate(flags => flags.enableOwnerStacks)) { [
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' + 'Math objects are not supported.\n' +
' <... value={Math}>\n' + ' <... value={Math}>\n' +
' ^^^^^^\n' + ' ^^^^^^',
' at (<anonymous>)', ],
]); {withoutStack: true},
} else { );
assertConsoleErrorDev(
[ ReactNoopFlightClient.read(transport);
'Only plain objects can be passed to Client Components from Server Components. ' + assertConsoleErrorDev([
'Math objects are not supported.\n' + 'Only plain objects can be passed to Client Components from Server Components. ' +
' <... value={Math}>\n' + 'Math objects are not supported.\n' +
' ^^^^^^', ' <... value={Math}>\n' +
'Only plain objects can be passed to Client Components from Server Components. ' + ' ^^^^^^\n' +
'Math objects are not supported.\n' + ' at (<anonymous>)',
' <... value={Math}>\n' + ]);
' ^^^^^^',
],
{withoutStack: true},
);
}
}); });
it('should warn in DEV if an object with symbols is passed to a Client Component', () => { it('should warn in DEV if an object with symbols is passed to a Client Component', () => {
@ -1867,42 +1718,24 @@ describe('ReactFlight', () => {
const transport = ReactNoopFlightServer.render( const transport = ReactNoopFlightServer.render(
<Client value={{[Symbol.iterator]: {}}} />, <Client value={{[Symbol.iterator]: {}}} />,
); );
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev(
assertConsoleErrorDev( [
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' + ' <... value={{}}>\n' +
' ^^^^\n', ' ^^^^',
]); ],
} else { {withoutStack: true},
assertConsoleErrorDev( );
[
'Only plain objects can be passed to Client Components from Server Components. ' + ReactNoopFlightClient.read(transport);
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' + assertConsoleErrorDev([
' ^^^^', 'Only plain objects can be passed to Client Components from Server Components. ' +
'Only plain objects can be passed to Client Components from Server Components. ' + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' + ' <... value={{}}>\n' +
' <... value={{}}>\n' + ' ^^^^\n',
' ^^^^', ]);
],
{withoutStack: true},
);
}
}); });
it('should warn in DEV if a special object is passed to a nested object in Client Component', () => { it('should warn in DEV if a special object is passed to a nested object in Client Component', () => {
@ -1915,36 +1748,20 @@ describe('ReactFlight', () => {
); );
ReactNoopFlightClient.read(transport); ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev([
assertConsoleErrorDev([ [
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
{withoutStack: true},
],
'Only plain objects can be passed to Client Components from Server Components. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' + ' <... value={{}}>\n' +
' ^^^^\n' + ' ^^^^',
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
],
{withoutStack: true}, {withoutStack: true},
); ],
} 'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^\n' +
' at (<anonymous>)',
]);
}); });
it('should warn in DEV if a special object is passed to a nested array in Client Component', () => { it('should warn in DEV if a special object is passed to a nested array in Client Component', () => {
@ -1956,36 +1773,20 @@ describe('ReactFlight', () => {
<Client value={['looooong string takes up noise', Math, <h1>hi</h1>]} />, <Client value={['looooong string takes up noise', Math, <h1>hi</h1>]} />,
); );
ReactNoopFlightClient.read(transport); ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev([
assertConsoleErrorDev([ [
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
{withoutStack: true},
],
'Only plain objects can be passed to Client Components from Server Components. ' + 'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' + 'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' + ' [..., Math, <h1/>]\n' +
' ^^^^\n' + ' ^^^^',
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
],
{withoutStack: true}, {withoutStack: true},
); ],
} 'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^\n' +
' at (<anonymous>)',
]);
}); });
it('should NOT warn in DEV for key getters', () => { it('should NOT warn in DEV for key getters', () => {
@ -2012,26 +1813,16 @@ describe('ReactFlight', () => {
jest.resetModules(); jest.resetModules();
jest.mock('react', () => React); jest.mock('react', () => React);
ReactNoopFlightClient.read(transport); ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev([
assertConsoleErrorDev([ 'Each child in a list should have a unique "key" prop. ' +
'Each child in a list should have a unique "key" prop. ' + 'See https://react.dev/link/warning-keys for more information.\n' +
'See https://react.dev/link/warning-keys for more information.\n' + ' in NoKey (at **)',
' in NoKey (at **)', 'Each child in a list should have a unique "key" prop. ' +
'Each child in a list should have a unique "key" prop. ' + 'See https://react.dev/link/warning-keys for more information.\n' +
'See https://react.dev/link/warning-keys for more information.\n' + ' in NoKey (at **)',
' in NoKey (at **)', ]);
]);
} else {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <div>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in NoKey (at **)',
]);
}
}); });
// @gate !__DEV__ || enableOwnerStacks
it('should warn in DEV a child is missing keys on a fragment', () => { it('should warn in DEV a child is missing keys on a fragment', () => {
// While we're on the server we need to have the Server version active to track component stacks. // While we're on the server we need to have the Server version active to track component stacks.
jest.resetModules(); jest.resetModules();
@ -2046,23 +1837,14 @@ describe('ReactFlight', () => {
jest.resetModules(); jest.resetModules();
jest.mock('react', () => React); jest.mock('react', () => React);
ReactNoopFlightClient.read(transport); ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev([
assertConsoleErrorDev([ 'Each child in a list should have a unique "key" prop. ' +
'Each child in a list should have a unique "key" prop. ' + 'See https://react.dev/link/warning-keys for more information.\n' +
'See https://react.dev/link/warning-keys for more information.\n' + ' in Fragment (at **)',
' in Fragment (at **)', 'Each child in a list should have a unique "key" prop. ' +
'Each child in a list should have a unique "key" prop. ' + 'See https://react.dev/link/warning-keys for more information.\n' +
'See https://react.dev/link/warning-keys for more information.\n' + ' in Fragment (at **)',
' in Fragment (at **)', ]);
]);
} else {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <div>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Fragment (at **)',
]);
}
}); });
it('should warn in DEV a child is missing keys in client component', async () => { it('should warn in DEV a child is missing keys in client component', async () => {
@ -2079,20 +1861,12 @@ describe('ReactFlight', () => {
ReactNoop.render(await ReactNoopFlightClient.read(transport)); ReactNoop.render(await ReactNoopFlightClient.read(transport));
}); });
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev([
assertConsoleErrorDev([ 'Each child in a list should have a unique "key" prop.\n\n' +
'Each child in a list should have a unique "key" prop.\n\n' + 'Check the top-level render call using <ParentClient>. ' +
'Check the top-level render call using <ParentClient>. ' + 'See https://react.dev/link/warning-keys for more information.\n' +
'See https://react.dev/link/warning-keys for more information.\n' + ' in div (at **)',
' in div (at **)', ]);
]);
} else {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]);
}
}); });
it('should error if a class instance is passed to a host component', () => { it('should error if a class instance is passed to a host component', () => {
@ -3039,9 +2813,7 @@ describe('ReactFlight', () => {
env: 'Server', env: 'Server',
key: null, key: null,
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in Object.<anonymous> (at **)',
? ' in Object.<anonymous> (at **)'
: undefined,
props: { props: {
transport: expect.arrayContaining([]), transport: expect.arrayContaining([]),
}, },
@ -3063,9 +2835,7 @@ describe('ReactFlight', () => {
env: 'third-party', env: 'third-party',
key: null, key: null,
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in Object.<anonymous> (at **)',
? ' in Object.<anonymous> (at **)'
: undefined,
props: {}, props: {},
}, },
{time: 14}, {time: 14},
@ -3082,9 +2852,7 @@ describe('ReactFlight', () => {
env: 'third-party', env: 'third-party',
key: null, key: null,
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in myLazy (at **)\n in lazyInitializer (at **)',
? ' in myLazy (at **)\n in lazyInitializer (at **)'
: undefined,
props: {}, props: {},
}, },
{time: 16}, {time: 16},
@ -3100,9 +2868,7 @@ describe('ReactFlight', () => {
env: 'third-party', env: 'third-party',
key: '3', key: '3',
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in Object.<anonymous> (at **)',
? ' in Object.<anonymous> (at **)'
: undefined,
props: {}, props: {},
}, },
{time: 12}, {time: 12},
@ -3176,9 +2942,7 @@ describe('ReactFlight', () => {
env: 'Server', env: 'Server',
key: null, key: null,
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in Object.<anonymous> (at **)',
? ' in Object.<anonymous> (at **)'
: undefined,
props: { props: {
transport: expect.arrayContaining([]), transport: expect.arrayContaining([]),
}, },
@ -3198,9 +2962,7 @@ describe('ReactFlight', () => {
env: 'Server', env: 'Server',
key: 'keyed', key: 'keyed',
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in ServerComponent (at **)',
? ' in ServerComponent (at **)'
: undefined,
props: { props: {
children: {}, children: {},
}, },
@ -3219,9 +2981,7 @@ describe('ReactFlight', () => {
env: 'third-party', env: 'third-party',
key: null, key: null,
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in Object.<anonymous> (at **)',
? ' in Object.<anonymous> (at **)'
: undefined,
props: {}, props: {},
}, },
{time: 12}, {time: 12},
@ -3335,19 +3095,13 @@ describe('ReactFlight', () => {
}); });
expect(sawReactPrefix).toBe(false); expect(sawReactPrefix).toBe(false);
if (__DEV__ && gate(flags => flags.enableOwnerStacks)) { if (__DEV__) {
expect(environments.slice(0, 4)).toEqual([ expect(environments.slice(0, 4)).toEqual([
'Server', 'Server',
'third-party', 'third-party',
'third-party', 'third-party',
'third-party', 'third-party',
]); ]);
} else if (__DEV__) {
expect(environments.slice(0, 3)).toEqual([
'third-party',
'third-party',
'third-party',
]);
} else { } else {
expect(environments).toEqual([]); expect(environments).toEqual([]);
} }
@ -3384,9 +3138,7 @@ describe('ReactFlight', () => {
env: 'A', env: 'A',
key: null, key: null,
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in Object.<anonymous> (at **)',
? ' in Object.<anonymous> (at **)'
: undefined,
props: {}, props: {},
}, },
{ {
@ -3402,7 +3154,7 @@ describe('ReactFlight', () => {
expect(ReactNoop).toMatchRenderedOutput(<div>hi</div>); expect(ReactNoop).toMatchRenderedOutput(<div>hi</div>);
}); });
// @gate __DEV__ && enableOwnerStacks // @gate __DEV__
it('replays logs, but not onError logs', async () => { it('replays logs, but not onError logs', async () => {
function foo() { function foo() {
return 'hello'; return 'hello';
@ -3574,9 +3326,7 @@ describe('ReactFlight', () => {
env: 'Server', env: 'Server',
key: null, key: null,
owner: null, owner: null,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in Object.<anonymous> (at **)',
? ' in Object.<anonymous> (at **)'
: undefined,
props: { props: {
firstName: 'Seb', firstName: 'Seb',
}, },
@ -3590,9 +3340,7 @@ describe('ReactFlight', () => {
env: 'Server', env: 'Server',
key: null, key: null,
owner: greetInfo, owner: greetInfo,
stack: gate(flag => flag.enableOwnerStacks) stack: ' in Greeting (at **)',
? ' in Greeting (at **)'
: undefined,
props: { props: {
children: expect.objectContaining({ children: expect.objectContaining({
type: 'span', type: 'span',
@ -3617,7 +3365,7 @@ describe('ReactFlight', () => {
expect(ReactNoop).toMatchRenderedOutput(<span>Hello, Seb</span>); expect(ReactNoop).toMatchRenderedOutput(<span>Hello, Seb</span>);
}); });
// @gate __DEV__ && enableOwnerStacks // @gate __DEV__
it('can get the component owner stacks during rendering in dev', () => { it('can get the component owner stacks during rendering in dev', () => {
let stack; let stack;
@ -3649,7 +3397,7 @@ describe('ReactFlight', () => {
); );
}); });
// @gate __DEV__ && enableOwnerStacks // @gate __DEV__
it('can track owner for a flight response created in another render', async () => { it('can track owner for a flight response created in another render', async () => {
jest.resetModules(); jest.resetModules();
jest.mock('react', () => ReactServer); jest.mock('react', () => ReactServer);
@ -3712,7 +3460,7 @@ describe('ReactFlight', () => {
); );
}); });
// @gate __DEV__ && enableOwnerStacks // @gate __DEV__
it('can get the component owner stacks for onError in dev', async () => { it('can get the component owner stacks for onError in dev', async () => {
const thrownError = new Error('hi'); const thrownError = new Error('hi');
let caughtError; let caughtError;
@ -3754,7 +3502,6 @@ describe('ReactFlight', () => {
); );
}); });
// @gate (enableOwnerStacks) || !__DEV__
it('should include only one component stack in replayed logs (if DevTools or polyfill adds them)', () => { it('should include only one component stack in replayed logs (if DevTools or polyfill adds them)', () => {
class MyError extends Error { class MyError extends Error {
toJSON() { toJSON() {

View File

@ -2347,10 +2347,7 @@ describe('ReactHooksInspectionIntegration', () => {
await act(async () => await LazyFoo); await act(async () => await LazyFoo);
assertConsoleErrorDev([ assertConsoleErrorDev([
'Foo: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.' + 'Foo: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in Foo (at **)\n' + ' in Suspense (at **)'),
]); ]);
const childFiber = renderer.root._currentFiber(); const childFiber = renderer.root._currentFiber();

View File

@ -917,7 +917,7 @@ export function createProfilingHooks({
// Creating a cache of component stacks won't help, generating a single stack is already expensive enough. // Creating a cache of component stacks won't help, generating a single stack is already expensive enough.
// We should find a way to lazily generate component stacks on demand, when user inspects a specific event. // We should find a way to lazily generate component stacks on demand, when user inspects a specific event.
// If we succeed with moving React DevTools Timeline Profiler to Performance panel, then Timeline Profiler would probably be removed. // If we succeed with moving React DevTools Timeline Profiler to Performance panel, then Timeline Profiler would probably be removed.
// If not, then once enableOwnerStacks is adopted, revisit this again and cache component stacks per Fiber, // Now that owner stacks are adopted, revisit this again and cache component stacks per Fiber,
// but only return them when needed, sending hundreds of component stacks is beyond the Bridge's bandwidth. // but only return them when needed, sending hundreds of component stacks is beyond the Bridge's bandwidth.
// Postprocess Profile data // Postprocess Profile data

View File

@ -10,8 +10,6 @@
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes'; import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import type {HydrationDiffNode} from 'react-reconciler/src/ReactFiberHydrationDiffs'; import type {HydrationDiffNode} from 'react-reconciler/src/ReactFiberHydrationDiffs';
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import { import {
current, current,
runWithFiberInDEV, runWithFiberInDEV,
@ -615,7 +613,7 @@ function validateDOMNesting(
ancestorDescription, ancestorDescription,
); );
} }
if (enableOwnerStacks && child) { if (child) {
// For debugging purposes find the nearest ancestor that caused the issue. // For debugging purposes find the nearest ancestor that caused the issue.
// The stack trace of this ancestor can be useful to find the cause. // The stack trace of this ancestor can be useful to find the cause.
// If the parent is a direct parent in the same owner, we don't bother. // If the parent is a direct parent in the same owner, we don't bother.

View File

@ -52,7 +52,6 @@ import {
enableLegacyFBSupport, enableLegacyFBSupport,
enableCreateEventHandleAPI, enableCreateEventHandleAPI,
enableScopeAPI, enableScopeAPI,
enableOwnerStacks,
disableCommentsAsDOMContainers, disableCommentsAsDOMContainers,
enableScrollEndPolyfill, enableScrollEndPolyfill,
} from 'shared/ReactFeatureFlags'; } from 'shared/ReactFeatureFlags';
@ -275,7 +274,7 @@ function processDispatchQueueItemsInOrder(
if (instance !== previousInstance && event.isPropagationStopped()) { if (instance !== previousInstance && event.isPropagationStopped()) {
return; return;
} }
if (__DEV__ && enableOwnerStacks && instance !== null) { if (__DEV__ && instance !== null) {
runWithFiberInDEV( runWithFiberInDEV(
instance, instance,
executeDispatch, executeDispatch,
@ -294,7 +293,7 @@ function processDispatchQueueItemsInOrder(
if (instance !== previousInstance && event.isPropagationStopped()) { if (instance !== previousInstance && event.isPropagationStopped()) {
return; return;
} }
if (__DEV__ && enableOwnerStacks && instance !== null) { if (__DEV__ && instance !== null) {
runWithFiberInDEV( runWithFiberInDEV(
instance, instance,
executeDispatch, executeDispatch,

View File

@ -75,8 +75,7 @@ describe('ReactChildReconciler', () => {
'This may happen if you return fn instead of <fn /> from render. ' + 'This may happen if you return fn instead of <fn /> from render. ' +
'Or maybe you meant to call this function rather than return it.\n' + 'Or maybe you meant to call this function rather than return it.\n' +
' <h1>{fn}</h1>\n' + ' <h1>{fn}</h1>\n' +
' in h1 (at **)' + ' in h1 (at **)',
(gate('enableOwnerStacks') ? '' : '\n in div (at **)'),
]); ]);
const node = container.firstChild; const node = container.firstChild;
@ -100,7 +99,6 @@ describe('ReactChildReconciler', () => {
'Keys should be unique so that components maintain their identity across updates. ' + 'Keys should be unique so that components maintain their identity across updates. ' +
'Non-unique keys may cause children to be duplicated and/or omitted — ' + 'Non-unique keys may cause children to be duplicated and/or omitted — ' +
'the behavior is unsupported and could change in a future version.\n' + 'the behavior is unsupported and could change in a future version.\n' +
(gate('enableOwnerStacks') ? '' : ' in div (at **)\n') +
' in div (at **)\n' + ' in div (at **)\n' +
' in Component (at **)', ' in Component (at **)',
]); ]);
@ -137,11 +135,7 @@ describe('ReactChildReconciler', () => {
'duplicated and/or omitted — the behavior is unsupported and ' + 'duplicated and/or omitted — the behavior is unsupported and ' +
'could change in a future version.\n' + 'could change in a future version.\n' +
' in div (at **)\n' + ' in div (at **)\n' +
(gate(flags => flags.enableOwnerStacks) ? '' : ' in div (at **)\n') +
' in Component (at **)\n' + ' in Component (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Parent (at **)\n') +
' in GrandParent (at **)', ' in GrandParent (at **)',
]); ]);
}); });
@ -165,7 +159,6 @@ describe('ReactChildReconciler', () => {
'duplicated and/or omitted — the behavior is unsupported and ' + 'duplicated and/or omitted — the behavior is unsupported and ' +
'could change in a future version.\n' + 'could change in a future version.\n' +
' in div (at **)\n' + ' in div (at **)\n' +
(gate(flags => flags.enableOwnerStacks) ? '' : ' in div (at **)\n') +
' in Component (at **)', ' in Component (at **)',
]); ]);
}); });
@ -201,11 +194,7 @@ describe('ReactChildReconciler', () => {
'duplicated and/or omitted — the behavior is unsupported and ' + 'duplicated and/or omitted — the behavior is unsupported and ' +
'could change in a future version.\n' + 'could change in a future version.\n' +
' in div (at **)\n' + ' in div (at **)\n' +
(gate(flags => flags.enableOwnerStacks) ? '' : ' in div (at **)\n') +
' in Component (at **)\n' + ' in Component (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Parent (at **)\n') +
' in GrandParent (at **)', ' in GrandParent (at **)',
]); ]);
}); });

View File

@ -407,17 +407,6 @@ describe('ReactComponent', () => {
const X = undefined; const X = undefined;
const XElement = <X />; const XElement = <X />;
if (gate(flags => !flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined. ' +
"You likely forgot to export your component from the file it's defined in, " +
'or you might have mixed up default and named imports.',
],
{withoutStack: true},
);
}
await expect(async () => { await expect(async () => {
await act(() => { await act(() => {
root.render(XElement); root.render(XElement);
@ -433,15 +422,6 @@ describe('ReactComponent', () => {
const Y = null; const Y = null;
const YElement = <Y />; const YElement = <Y />;
if (gate(flags => !flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: null.',
],
{withoutStack: true},
);
}
await expect(async () => { await expect(async () => {
await act(() => { await act(() => {
root.render(YElement); root.render(YElement);
@ -453,15 +433,6 @@ describe('ReactComponent', () => {
const Z = true; const Z = true;
const ZElement = <Z />; const ZElement = <Z />;
if (gate(flags => !flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: boolean.',
],
{withoutStack: true},
);
}
await expect(async () => { await expect(async () => {
await act(() => { await act(() => {
root.render(ZElement); root.render(ZElement);
@ -506,26 +477,6 @@ describe('ReactComponent', () => {
'\n\nCheck the render method of `Bar`.' '\n\nCheck the render method of `Bar`.'
: ''), : ''),
); );
if (!gate('enableOwnerStacks')) {
assertConsoleErrorDev([
'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined.' +
(__DEV__
? " You likely forgot to export your component from the file it's defined in, " +
'or you might have mixed up default and named imports.\n' +
' in Bar (at **)\n' +
' in Foo (at **)'
: ''),
'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined.' +
(__DEV__
? " You likely forgot to export your component from the file it's defined in, " +
'or you might have mixed up default and named imports.\n' +
' in Bar (at **)\n' +
' in Foo (at **)'
: ''),
]);
}
}); });
it('throws if a plain object is used as a child', async () => { it('throws if a plain object is used as a child', async () => {
@ -693,9 +644,6 @@ describe('ReactComponent', () => {
'Or maybe you meant to call this function rather than return it.\n' + 'Or maybe you meant to call this function rather than return it.\n' +
' <span>{Foo}</span>\n' + ' <span>{Foo}</span>\n' +
' in span (at **)\n' + ' in span (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in div (at **)\n') +
' in Foo (at **)', ' in Foo (at **)',
]); ]);
}); });
@ -753,9 +701,6 @@ describe('ReactComponent', () => {
'Or maybe you meant to call this function rather than return it.\n' + 'Or maybe you meant to call this function rather than return it.\n' +
' <span>{Foo}</span>\n' + ' <span>{Foo}</span>\n' +
' in span (at **)\n' + ' in span (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in div (at **)\n') +
' in Foo (at **)', ' in Foo (at **)',
]); ]);
await act(() => { await act(() => {

View File

@ -1396,9 +1396,6 @@ describe('ReactCompositeComponent', () => {
'Cannot update a component (`A`) while rendering a different component (`B`). ' + 'Cannot update a component (`A`) while rendering a different component (`B`). ' +
'To locate the bad setState() call inside `B`, ' + 'To locate the bad setState() call inside `B`, ' +
'follow the stack trace as described in https://react.dev/link/setstate-in-render\n' + 'follow the stack trace as described in https://react.dev/link/setstate-in-render\n' +
(gate('enableOwnerStacks')
? ''
: ' in B (at **)\n' + ' in div (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
]); ]);

View File

@ -545,7 +545,6 @@ describe('ReactDOM', () => {
// ReactDOM(App > div > span) // ReactDOM(App > div > span)
'Invalid ARIA attribute `ariaTypo`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + 'Invalid ARIA attribute `ariaTypo`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
(gate(flags => flags.enableOwnerStacks) ? '' : ' in div (at **)\n') +
' in App (at **)', ' in App (at **)',
// ReactDOM(App > div > ServerEntry) >>> ReactDOMServer(Child) >>> ReactDOMServer(App2) >>> ReactDOMServer(blink) // ReactDOM(App > div > ServerEntry) >>> ReactDOMServer(Child) >>> ReactDOMServer(App2) >>> ReactDOMServer(blink)
'Invalid ARIA attribute `ariaTypo2`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + 'Invalid ARIA attribute `ariaTypo2`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
@ -562,7 +561,6 @@ describe('ReactDOM', () => {
// ReactDOM(App > div > font) // ReactDOM(App > div > font)
'Invalid ARIA attribute `ariaTypo5`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + 'Invalid ARIA attribute `ariaTypo5`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
' in font (at **)\n' + ' in font (at **)\n' +
(gate(flags => flags.enableOwnerStacks) ? '' : ' in div (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
}); });

View File

@ -1845,8 +1845,7 @@ describe('ReactDOMComponent', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'The tag <menuitem> is unrecognized in this browser. ' + 'The tag <menuitem> is unrecognized in this browser. ' +
'If you meant to render a React component, start its name with an uppercase letter.\n' + 'If you meant to render a React component, start its name with an uppercase letter.\n' +
' in menuitem (at **)' + ' in menuitem (at **)',
(gate('enableOwnerStacks') ? '' : '\n in menu (at **)'),
]); ]);
}); });
@ -2242,10 +2241,7 @@ describe('ReactDOMComponent', () => {
'> <div>\n' + '> <div>\n' +
'> <tr>\n' + '> <tr>\n' +
' ...\n' + ' ...\n' +
'\n in tr (at **)' + '\n in tr (at **)',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in div (at **)'),
]); ]);
}); });
@ -2264,10 +2260,7 @@ describe('ReactDOMComponent', () => {
'In HTML, <p> cannot be a descendant of <p>.\n' + 'In HTML, <p> cannot be a descendant of <p>.\n' +
'This will cause a hydration error.' + 'This will cause a hydration error.' +
// There is no outer `p` here because root container is not part of the stack. // There is no outer `p` here because root container is not part of the stack.
'\n in p (at **)' + '\n in p (at **)',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in span (at **)'),
]); ]);
}); });
@ -2294,92 +2287,48 @@ describe('ReactDOMComponent', () => {
await act(() => { await act(() => {
root.render(<Foo />); root.render(<Foo />);
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'In HTML, <tr> cannot be a child of ' +
? [ '<table>. Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated ' +
'In HTML, <tr> cannot be a child of ' + 'by the browser.\n' +
'<table>. Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated ' + 'This will cause a hydration error.\n' +
'by the browser.\n' + '\n' +
'This will cause a hydration error.\n' + ' <Foo>\n' +
'\n' + '> <table>\n' +
' <Foo>\n' + ' <Row>\n' +
'> <table>\n' + '> <tr>\n' +
' <Row>\n' + ' ...\n' +
'> <tr>\n' + '\n in tr (at **)' +
' ...\n' + '\n in Row (at **)' +
'\n in tr (at **)' + '\n in Foo (at **)',
'\n in Row (at **)' + '<table> cannot contain a nested <tr>.\nSee this log for the ancestor stack trace.' +
'\n in Foo (at **)', '\n in table (at **)' +
'<table> cannot contain a nested <tr>.\nSee this log for the ancestor stack trace.' + '\n in Foo (at **)',
'\n in table (at **)' + 'In HTML, text nodes cannot be a ' +
'\n in Foo (at **)', 'child of <tr>.\n' +
'In HTML, text nodes cannot be a ' + 'This will cause a hydration error.\n' +
'child of <tr>.\n' + '\n' +
'This will cause a hydration error.\n' + ' <Foo>\n' +
'\n' + ' <table>\n' +
' <Foo>\n' + ' <Row>\n' +
' <table>\n' + ' <tr>\n' +
' <Row>\n' + '> x\n' +
' <tr>\n' + ' ...\n' +
'> x\n' + '\n in tr (at **)' +
' ...\n' + '\n in Row (at **)' +
'\n in tr (at **)' + '\n in Foo (at **)',
'\n in Row (at **)' + 'In HTML, whitespace text nodes cannot ' +
'\n in Foo (at **)', "be a child of <table>. Make sure you don't have any extra " +
'In HTML, whitespace text nodes cannot ' + 'whitespace between tags on each line of your source code.\n' +
"be a child of <table>. Make sure you don't have any extra " + 'This will cause a hydration error.\n' +
'whitespace between tags on each line of your source code.\n' + '\n' +
'This will cause a hydration error.\n' + ' <Foo>\n' +
'\n' + '> <table>\n' +
' <Foo>\n' + ' <Row>\n' +
'> <table>\n' + '> {" "}\n' +
' <Row>\n' + '\n in table (at **)' +
'> {" "}\n' + '\n in Foo (at **)',
'\n in table (at **)' + ]);
'\n in Foo (at **)',
]
: [
'In HTML, <tr> cannot be a child of ' +
'<table>. Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated ' +
'by the browser.\n' +
'This will cause a hydration error.\n' +
'\n' +
' <Foo>\n' +
'> <table>\n' +
' <Row>\n' +
'> <tr>\n' +
' ...\n' +
'\n in tr (at **)' +
'\n in Row (at **)' +
'\n in table (at **)' +
'\n in Foo (at **)',
'In HTML, text nodes cannot be a ' +
'child of <tr>.\n' +
'This will cause a hydration error.\n' +
'\n' +
' <Foo>\n' +
' <table>\n' +
' <Row>\n' +
' <tr>\n' +
'> x\n' +
' ...\n' +
'\n in tr (at **)' +
'\n in Row (at **)' +
'\n in table (at **)' +
'\n in Foo (at **)',
'In HTML, whitespace text nodes cannot ' +
"be a child of <table>. Make sure you don't have any extra " +
'whitespace between tags on each line of your source code.\n' +
'This will cause a hydration error.\n' +
'\n' +
' <Foo>\n' +
'> <table>\n' +
' <Row>\n' +
'> {" "}\n' +
'\n in table (at **)' +
'\n in Foo (at **)',
],
);
}); });
it('warns nicely for updating table rows to use text', async () => { it('warns nicely for updating table rows to use text', async () => {
@ -2445,12 +2394,7 @@ describe('ReactDOMComponent', () => {
' <tr>\n' + ' <tr>\n' +
'> text\n' + '> text\n' +
'\n in tr (at **)' + '\n in tr (at **)' +
'\n in Row (at **)' + '\n in Row (at **)',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in tbody (at **)' +
'\n in table (at **)' +
'\n in Foo (at **)'),
]); ]);
}); });
@ -2477,49 +2421,28 @@ describe('ReactDOMComponent', () => {
await act(() => { await act(() => {
root.render(<App1 />); root.render(<App1 />);
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'In HTML, <tr> cannot be a child of <table>. ' +
? [ 'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' +
'In HTML, <tr> cannot be a child of <table>. ' + 'This will cause a hydration error.\n' +
'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' + '\n' +
'This will cause a hydration error.\n' + ' <App1>\n' +
'\n' + ' <Viz1>\n' +
' <App1>\n' + '> <table>\n' +
' <Viz1>\n' + ' <FancyRow>\n' +
'> <table>\n' + ' <Row>\n' +
' <FancyRow>\n' + '> <tr>\n' +
' <Row>\n' + '\n in tr (at **)' +
'> <tr>\n' + '\n in Row (at **)' +
'\n in tr (at **)' + '\n in FancyRow (at **)' +
'\n in Row (at **)' + '\n in Viz1 (at **)' +
'\n in FancyRow (at **)' + '\n in App1 (at **)',
'\n in Viz1 (at **)' + '<table> cannot contain a nested <tr>.\n' +
'\n in App1 (at **)', 'See this log for the ancestor stack trace.\n' +
'<table> cannot contain a nested <tr>.\n' + ' in table (at **)\n' +
'See this log for the ancestor stack trace.\n' + ' in Viz1 (at **)\n' +
' in table (at **)\n' + ' in App1 (at **)',
' in Viz1 (at **)\n' + ]);
' in App1 (at **)',
]
: [
'In HTML, <tr> cannot be a child of <table>. ' +
'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' +
'This will cause a hydration error.\n' +
'\n' +
' <App1>\n' +
' <Viz1>\n' +
'> <table>\n' +
' <FancyRow>\n' +
' <Row>\n' +
'> <tr>\n' +
'\n in tr (at **)' +
'\n in Row (at **)' +
'\n in FancyRow (at **)' +
'\n in table (at **)' +
'\n in Viz1 (at **)' +
'\n in App1 (at **)',
],
);
}); });
it('gives useful context in warnings 2', async () => { it('gives useful context in warnings 2', async () => {
@ -2558,57 +2481,32 @@ describe('ReactDOMComponent', () => {
await act(() => { await act(() => {
root.render(<App2 />); root.render(<App2 />);
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'In HTML, <tr> cannot be a child of <table>. ' +
? [ 'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' +
'In HTML, <tr> cannot be a child of <table>. ' + 'This will cause a hydration error.\n' +
'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' + '\n' +
'This will cause a hydration error.\n' + ' <App2>\n' +
'\n' + ' <Viz2>\n' +
' <App2>\n' + ' <FancyTable>\n' +
' <Viz2>\n' + ' <Table>\n' +
' <FancyTable>\n' + '> <table>\n' +
' <Table>\n' + ' <FancyRow>\n' +
'> <table>\n' + ' <Row>\n' +
' <FancyRow>\n' + '> <tr>\n' +
' <Row>\n' + '\n in tr (at **)' +
'> <tr>\n' + '\n in Row (at **)' +
'\n in tr (at **)' + '\n in FancyRow (at **)' +
'\n in Row (at **)' + '\n in Viz2 (at **)' +
'\n in FancyRow (at **)' + '\n in App2 (at **)',
'\n in Viz2 (at **)' + '<table> cannot contain a nested <tr>.\n' +
'\n in App2 (at **)', 'See this log for the ancestor stack trace.\n' +
'<table> cannot contain a nested <tr>.\n' + ' in table (at **)\n' +
'See this log for the ancestor stack trace.\n' + ' in Table (at **)\n' +
' in table (at **)\n' + ' in FancyTable (at **)\n' +
' in Table (at **)\n' + ' in Viz2 (at **)\n' +
' in FancyTable (at **)\n' + ' in App2 (at **)',
' in Viz2 (at **)\n' + ]);
' in App2 (at **)',
]
: [
'In HTML, <tr> cannot be a child of <table>. ' +
'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' +
'This will cause a hydration error.\n' +
'\n' +
' <App2>\n' +
' <Viz2>\n' +
' <FancyTable>\n' +
' <Table>\n' +
'> <table>\n' +
' <FancyRow>\n' +
' <Row>\n' +
'> <tr>\n' +
'\n in tr (at **)' +
'\n in Row (at **)' +
'\n in FancyRow (at **)' +
'\n in table (at **)' +
'\n in Table (at **)' +
'\n in FancyTable (at **)' +
'\n in Viz2 (at **)' +
'\n in App2 (at **)',
],
);
}); });
it('gives useful context in warnings 3', async () => { it('gives useful context in warnings 3', async () => {
@ -2640,47 +2538,26 @@ describe('ReactDOMComponent', () => {
</FancyTable>, </FancyTable>,
); );
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'In HTML, <tr> cannot be a child of <table>. ' +
? [ 'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' +
'In HTML, <tr> cannot be a child of <table>. ' + 'This will cause a hydration error.\n' +
'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' + '\n' +
'This will cause a hydration error.\n' + ' <FancyTable>\n' +
'\n' + ' <Table>\n' +
' <FancyTable>\n' + '> <table>\n' +
' <Table>\n' + ' <FancyRow>\n' +
'> <table>\n' + ' <Row>\n' +
' <FancyRow>\n' + '> <tr>\n' +
' <Row>\n' + '\n in tr (at **)' +
'> <tr>\n' + '\n in Row (at **)' +
'\n in tr (at **)' + '\n in FancyRow (at **)',
'\n in Row (at **)' + '<table> cannot contain a nested <tr>.\n' +
'\n in FancyRow (at **)', 'See this log for the ancestor stack trace.' +
'<table> cannot contain a nested <tr>.\n' + '\n in table (at **)' +
'See this log for the ancestor stack trace.' + '\n in Table (at **)' +
'\n in table (at **)' + '\n in FancyTable (at **)',
'\n in Table (at **)' + ]);
'\n in FancyTable (at **)',
]
: [
'In HTML, <tr> cannot be a child of <table>. ' +
'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' +
'This will cause a hydration error.\n' +
'\n' +
' <FancyTable>\n' +
' <Table>\n' +
'> <table>\n' +
' <FancyRow>\n' +
' <Row>\n' +
'> <tr>\n' +
'\n in tr (at **)' +
'\n in Row (at **)' +
'\n in FancyRow (at **)' +
'\n in table (at **)' +
'\n in Table (at **)' +
'\n in FancyTable (at **)',
],
);
}); });
it('gives useful context in warnings 4', async () => { it('gives useful context in warnings 4', async () => {
@ -2701,39 +2578,22 @@ describe('ReactDOMComponent', () => {
</table>, </table>,
); );
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'In HTML, <tr> cannot be a child of <table>. ' +
? [ 'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' +
'In HTML, <tr> cannot be a child of <table>. ' + 'This will cause a hydration error.\n' +
'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' + '\n' +
'This will cause a hydration error.\n' + '> <table>\n' +
'\n' + ' <FancyRow>\n' +
'> <table>\n' + ' <Row>\n' +
' <FancyRow>\n' + '> <tr>\n' +
' <Row>\n' + '\n in tr (at **)' +
'> <tr>\n' + '\n in Row (at **)' +
'\n in tr (at **)' + '\n in FancyRow (at **)',
'\n in Row (at **)' + '<table> cannot contain a nested <tr>.\n' +
'\n in FancyRow (at **)', 'See this log for the ancestor stack trace.' +
'<table> cannot contain a nested <tr>.\n' + '\n in table (at **)',
'See this log for the ancestor stack trace.' + ]);
'\n in table (at **)',
]
: [
'In HTML, <tr> cannot be a child of <table>. ' +
'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' +
'This will cause a hydration error.\n' +
'\n' +
'> <table>\n' +
' <FancyRow>\n' +
' <Row>\n' +
'> <tr>\n' +
'\n in tr (at **)' +
'\n in Row (at **)' +
'\n in FancyRow (at **)' +
'\n in table (at **)',
],
);
}); });
it('gives useful context in warnings 5', async () => { it('gives useful context in warnings 5', async () => {
@ -2758,39 +2618,22 @@ describe('ReactDOMComponent', () => {
</FancyTable>, </FancyTable>,
); );
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'In HTML, <tr> cannot be a child of <table>. ' +
? [ 'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' +
'In HTML, <tr> cannot be a child of <table>. ' + 'This will cause a hydration error.\n' +
'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' + '\n' +
'This will cause a hydration error.\n' + ' <FancyTable>\n' +
'\n' + ' <Table>\n' +
' <FancyTable>\n' + '> <table>\n' +
' <Table>\n' + '> <tr>\n' +
'> <table>\n' + '\n in tr (at **)',
'> <tr>\n' + '<table> cannot contain a nested <tr>.\n' +
'\n in tr (at **)', 'See this log for the ancestor stack trace.' +
'<table> cannot contain a nested <tr>.\n' + '\n in table (at **)' +
'See this log for the ancestor stack trace.' + '\n in Table (at **)' +
'\n in table (at **)' + '\n in FancyTable (at **)',
'\n in Table (at **)' + ]);
'\n in FancyTable (at **)',
]
: [
'In HTML, <tr> cannot be a child of <table>. ' +
'Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser.\n' +
'This will cause a hydration error.\n' +
'\n' +
' <FancyTable>\n' +
' <Table>\n' +
'> <table>\n' +
'> <tr>\n' +
'\n in tr (at **)' +
'\n in table (at **)' +
'\n in Table (at **)' +
'\n in FancyTable (at **)',
],
);
class Link extends React.Component { class Link extends React.Component {
render() { render() {
@ -2807,40 +2650,22 @@ describe('ReactDOMComponent', () => {
</Link>, </Link>,
); );
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'In HTML, <a> cannot be a descendant of <a>.\n' +
? [ 'This will cause a hydration error.\n' +
'In HTML, <a> cannot be a descendant of <a>.\n' + '\n' +
'This will cause a hydration error.\n' + ' <Link>\n' +
'\n' + '> <a>\n' +
' <Link>\n' + ' <div>\n' +
'> <a>\n' + ' <Link>\n' +
' <div>\n' + '> <a>\n' +
' <Link>\n' + '\n in a (at **)' +
'> <a>\n' + '\n in Link (at **)',
'\n in a (at **)' + '<a> cannot contain a nested <a>.\n' +
'\n in Link (at **)', 'See this log for the ancestor stack trace.' +
'<a> cannot contain a nested <a>.\n' + '\n in a (at **)' +
'See this log for the ancestor stack trace.' + '\n in Link (at **)',
'\n in a (at **)' + ]);
'\n in Link (at **)',
]
: [
'In HTML, <a> cannot be a descendant of <a>.\n' +
'This will cause a hydration error.\n' +
'\n' +
' <Link>\n' +
'> <a>\n' +
' <div>\n' +
' <Link>\n' +
'> <a>\n' +
'\n in a (at **)' +
'\n in Link (at **)' +
'\n in div (at **)' +
'\n in a (at **)' +
'\n in Link (at **)',
],
);
}); });
it('should warn about incorrect casing on properties (ssr)', () => { it('should warn about incorrect casing on properties (ssr)', () => {
@ -3099,11 +2924,9 @@ describe('ReactDOMComponent', () => {
}); });
assertConsoleErrorDev([ assertConsoleErrorDev([
'Invalid DOM property `class`. Did you mean `className`?\n' + 'Invalid DOM property `class`. Did you mean `className`?\n' +
' in span (at **)' + ' in span (at **)',
(gate('enableOwnerStacks') ? '' : '\n in div (at **)'),
'Invalid event handler property `onclick`. Did you mean `onClick`?\n' + 'Invalid event handler property `onclick`. Did you mean `onClick`?\n' +
' in strong (at **)' + ' in strong (at **)',
(gate('enableOwnerStacks') ? '' : '\n in div (at **)'),
]); ]);
}); });
@ -3119,12 +2942,10 @@ describe('ReactDOMComponent', () => {
); );
assertConsoleErrorDev([ assertConsoleErrorDev([
'Invalid DOM property `class`. Did you mean `className`?\n' + 'Invalid DOM property `class`. Did you mean `className`?\n' +
' in span (at **)' + ' in span (at **)',
(gate('enableOwnerStacks') ? '' : '\n in div (at **)'),
'Invalid event handler property `onclick`. ' + 'Invalid event handler property `onclick`. ' +
'React events use the camelCase naming convention, for example `onClick`.\n' + 'React events use the camelCase naming convention, for example `onClick`.\n' +
' in strong (at **)' + ' in strong (at **)',
(gate('enableOwnerStacks') ? '' : '\n in div (at **)'),
]); ]);
}); });
@ -3175,12 +2996,10 @@ describe('ReactDOMComponent', () => {
'Invalid DOM property `class`. Did you mean `className`?\n' + 'Invalid DOM property `class`. Did you mean `className`?\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Child1 (at **)\n' + ' in Child1 (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in div (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
'Invalid event handler property `onclick`. Did you mean `onClick`?\n' + 'Invalid event handler property `onclick`. Did you mean `onClick`?\n' +
' in strong (at **)\n' + ' in strong (at **)\n' +
' in Child3 (at **)\n' + ' in Child3 (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in div (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
]); ]);
}); });
@ -3230,13 +3049,11 @@ describe('ReactDOMComponent', () => {
'Invalid DOM property `class`. Did you mean `className`?\n' + 'Invalid DOM property `class`. Did you mean `className`?\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Child1 (at **)\n' + ' in Child1 (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in div (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
'Invalid event handler property `onclick`. ' + 'Invalid event handler property `onclick`. ' +
'React events use the camelCase naming convention, for example `onClick`.\n' + 'React events use the camelCase naming convention, for example `onClick`.\n' +
' in strong (at **)\n' + ' in strong (at **)\n' +
' in Child3 (at **)\n' + ' in Child3 (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in div (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
]); ]);
}); });
@ -3362,8 +3179,7 @@ describe('ReactDOMComponent', () => {
}); });
assertConsoleErrorDev([ assertConsoleErrorDev([
'Invalid DOM property `arabic-form`. Did you mean `arabicForm`?\n' + 'Invalid DOM property `arabic-form`. Did you mean `arabicForm`?\n' +
' in text (at **)' + ' in text (at **)',
(gate('enableOwnerStacks') ? '' : '\n in svg (at **)'),
]); ]);
const text = el.querySelector('text'); const text = el.querySelector('text');
@ -3844,8 +3660,7 @@ describe('ReactDOMComponent', () => {
}); });
assertConsoleErrorDev([ assertConsoleErrorDev([
'Invalid DOM property `x-height`. Did you mean `xHeight`?\n' + 'Invalid DOM property `x-height`. Did you mean `xHeight`?\n' +
' in font-face (at **)' + ' in font-face (at **)',
(gate('enableOwnerStacks') ? '' : '\n in svg (at **)'),
]); ]);
expect(el.querySelector('font-face').hasAttribute('x-height')).toBe( expect(el.querySelector('font-face').hasAttribute('x-height')).toBe(
@ -3871,8 +3686,7 @@ describe('ReactDOMComponent', () => {
'whatever="false" or whatever={value.toString()}.\n\n' + 'whatever="false" or whatever={value.toString()}.\n\n' +
'If you used to conditionally omit it with whatever={condition && value}, ' + 'If you used to conditionally omit it with whatever={condition && value}, ' +
'pass whatever={condition ? value : undefined} instead.\n' + 'pass whatever={condition ? value : undefined} instead.\n' +
' in font-face (at **)' + ' in font-face (at **)',
(gate('enableOwnerStacks') ? '' : '\n in svg (at **)'),
]); ]);
expect(el.querySelector('font-face').hasAttribute('whatever')).toBe( expect(el.querySelector('font-face').hasAttribute('whatever')).toBe(

View File

@ -751,7 +751,6 @@ describe('ReactDOMFiber', () => {
' in Parent (at **)', ' in Parent (at **)',
'Component uses the legacy contextTypes API which will soon be removed. ' + 'Component uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in Component (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
]); ]);
expect(container.innerHTML).toBe(''); expect(container.innerHTML).toBe('');

View File

@ -386,7 +386,6 @@ describe('ReactDOMFizzForm', () => {
'Cannot specify a formTarget for a button that specifies a function as a formAction. ' + 'Cannot specify a formTarget for a button that specifies a function as a formAction. ' +
'The function will always be executed in the same window.\n' + 'The function will always be executed in the same window.\n' +
' in input (at **)\n' + ' in input (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in form (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
let root; let root;

View File

@ -1843,15 +1843,9 @@ describe('ReactDOMFizzServer', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'<inCorrectTag /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.' + '<inCorrectTag /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.' +
'\n' + '\n' +
(gate(flags => flags.enableOwnerStacks) ' in inCorrectTag (at **)\n' +
? ' in inCorrectTag (at **)\n' + ' in C (at **)\n' +
' in C (at **)\n' + ' in A (at **)',
' in A (at **)'
: ' in inCorrectTag (at **)\n' +
' in C (at **)\n' +
' in Suspense (at **)\n' +
' in div (at **)\n' +
' in A (at **)'),
]); ]);
await act(() => { await act(() => {
@ -1862,17 +1856,11 @@ describe('ReactDOMFizzServer', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\nCheck the render method of `B`.' + 'Each child in a list should have a unique "key" prop.\n\nCheck the render method of `B`.' +
' See https://react.dev/link/warning-keys for more information.\n' + ' See https://react.dev/link/warning-keys for more information.\n' +
(gate(flags => flags.enableOwnerStacks) ' in span (at **)\n' +
? ' in span (at **)\n' + ' in mapper (at **)\n' +
' in mapper (at **)\n' + ' in Array.map (at **)\n' +
' in Array.map (at **)\n' + ' in B (at **)\n' +
' in B (at **)\n' + ' in A (at **)',
' in A (at **)'
: ' in span (at **)\n' +
' in B (at **)\n' +
' in Suspense (at **)\n' +
' in div (at **)\n' +
' in A (at **)'),
]); ]);
expect(getVisibleChildren(container)).toEqual( expect(getVisibleChildren(container)).toEqual(
@ -1954,13 +1942,7 @@ describe('ReactDOMFizzServer', () => {
' in TestProvider (at **)', ' in TestProvider (at **)',
'TestConsumer uses the legacy contextTypes API which will soon be removed. ' + 'TestConsumer uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in TestConsumer (at **)' + ' in TestConsumer (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in TestProvider (at **)' +
'\n in Suspense (at **)' +
'\n in div (at **)' +
'\n in TestProvider (at **)'),
]); ]);
expect(getVisibleChildren(container)).toEqual( expect(getVisibleChildren(container)).toEqual(
<div> <div>
@ -5871,7 +5853,6 @@ describe('ReactDOMFizzServer', () => {
'If your `children` prop is using this form try rewriting it using a template string: ' + 'If your `children` prop is using this form try rewriting it using a template string: ' +
'<title>{`hello ${nameOfUser}`}</title>.\n' + '<title>{`hello ${nameOfUser}`}</title>.\n' +
' in title (at **)\n' + ' in title (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in head (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
@ -5917,7 +5898,6 @@ describe('ReactDOMFizzServer', () => {
'React Component try moving the <title> tag into that component. ' + 'React Component try moving the <title> tag into that component. ' +
'If the `children` of <title> is some HTML markup change it to be Text only to be valid HTML.\n' + 'If the `children` of <title> is some HTML markup change it to be Text only to be valid HTML.\n' +
' in title (at **)\n' + ' in title (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in head (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
// object titles are toStringed when float is on // object titles are toStringed when float is on
@ -5961,7 +5941,6 @@ describe('ReactDOMFizzServer', () => {
'string or number value if so. Otherwise implement a `toString` method that React can ' + 'string or number value if so. Otherwise implement a `toString` method that React can ' +
'use to produce a valid <title>.\n' + 'use to produce a valid <title>.\n' +
' in title (at **)\n' + ' in title (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in head (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
// object titles are toStringed when float is on // object titles are toStringed when float is on
@ -6545,23 +6524,11 @@ describe('ReactDOMFizzServer', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'A script element was rendered with a number for children. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.' + 'A script element was rendered with a number for children. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.' +
componentStack( componentStack(['script', 'App']),
gate(flags => flags.enableOwnerStacks)
? ['script', 'App']
: ['script', 'body', 'html', 'App'],
),
'A script element was rendered with an array for children. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.' + 'A script element was rendered with an array for children. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.' +
componentStack( componentStack(['script', 'App']),
gate(flags => flags.enableOwnerStacks)
? ['script', 'App']
: ['script', 'body', 'html', 'App'],
),
'A script element was rendered with something unexpected for children. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.' + 'A script element was rendered with something unexpected for children. If script element has children it must be a single string. Consider using dangerouslySetInnerHTML or passing a plain string as children.' +
componentStack( componentStack(['script', 'App']),
gate(flags => flags.enableOwnerStacks)
? ['script', 'App']
: ['script', 'body', 'html', 'App'],
),
]); ]);
}); });
@ -8544,7 +8511,7 @@ describe('ReactDOMFizzServer', () => {
expect(document.body.textContent).toBe('HelloWorld'); expect(document.body.textContent).toBe('HelloWorld');
}); });
// @gate __DEV__ && enableOwnerStacks // @gate __DEV__
it('can get the component owner stacks during rendering in dev', async () => { it('can get the component owner stacks during rendering in dev', async () => {
let stack; let stack;
@ -8577,7 +8544,7 @@ describe('ReactDOMFizzServer', () => {
); );
}); });
// @gate __DEV__ && enableOwnerStacks // @gate __DEV__
it('can get the component owner stacks for onError in dev', async () => { it('can get the component owner stacks for onError in dev', async () => {
const thrownError = new Error('hi'); const thrownError = new Error('hi');
let caughtError; let caughtError;
@ -9111,56 +9078,30 @@ describe('ReactDOMFizzServer', () => {
</body> </body>
</html>, </html>,
); );
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev([
assertConsoleErrorDev([ [
[ 'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.', {withoutStack: true},
{withoutStack: true}, ],
], 'In HTML, <meta> cannot be a child of <html>.\nThis will cause a hydration error.' +
'In HTML, <meta> cannot be a child of <html>.\nThis will cause a hydration error.' + '\n' +
'\n' + '\n <App>' +
'\n <App>' + '\n> <html>' +
'\n> <html>' + '\n <Suspense fallback="this fallb...">' +
'\n <Suspense fallback="this fallb...">' + '\n <meta>' +
'\n <meta>' + '\n> <meta itemProp="" content="before">' +
'\n> <meta itemProp="" content="before">' + '\n ...' +
'\n ...' + '\n' +
'\n' + '\n in meta (at **)' +
'\n in meta (at **)' + '\n in App (at **)',
'\n in App (at **)', '<html> cannot contain a nested <meta>.\nSee this log for the ancestor stack trace.' +
'<html> cannot contain a nested <meta>.\nSee this log for the ancestor stack trace.' + '\n in html (at **)' +
'\n in html (at **)' + '\n in App (at **)',
'\n in App (at **)', [
[ 'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.', {withoutStack: true},
{withoutStack: true}, ],
], ]);
]);
} else {
assertConsoleErrorDev([
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.' +
'\n in Suspense (at **)' +
'\n in html (at **)' +
'\n in App (at **)',
'In HTML, <meta> cannot be a child of <html>.\nThis will cause a hydration error.' +
'\n' +
'\n <App>' +
'\n> <html>' +
'\n <Suspense fallback="this fallb...">' +
'\n <meta>' +
'\n> <meta itemProp="" content="before">' +
'\n ...' +
'\n' +
'\n in meta (at **)' +
'\n in Suspense (at **)' +
'\n in html (at **)' +
'\n in App (at **)',
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.' +
'\n in Suspense (at **)' +
'\n in html (at **)' +
'\n in App (at **)',
]);
}
await root.unmount(); await root.unmount();
expect(getVisibleChildren(document)).toEqual( expect(getVisibleChildren(document)).toEqual(
@ -9253,56 +9194,30 @@ describe('ReactDOMFizzServer', () => {
</body> </body>
</html>, </html>,
); );
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev([
assertConsoleErrorDev([ [
[ 'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.', {withoutStack: true},
{withoutStack: true}, ],
], 'In HTML, <meta> cannot be a child of <html>.\nThis will cause a hydration error.' +
'In HTML, <meta> cannot be a child of <html>.\nThis will cause a hydration error.' + '\n' +
'\n' + '\n <App>' +
'\n <App>' + '\n> <html>' +
'\n> <html>' + '\n <Suspense fallback="this fallb...">' +
'\n <Suspense fallback="this fallb...">' + '\n <meta>' +
'\n <meta>' + '\n> <meta itemProp="" content="before">' +
'\n> <meta itemProp="" content="before">' + '\n ...' +
'\n ...' + '\n' +
'\n' + '\n in meta (at **)' +
'\n in meta (at **)' + '\n in App (at **)',
'\n in App (at **)', '<html> cannot contain a nested <meta>.\nSee this log for the ancestor stack trace.' +
'<html> cannot contain a nested <meta>.\nSee this log for the ancestor stack trace.' + '\n in html (at **)' +
'\n in html (at **)' + '\n in App (at **)',
'\n in App (at **)', [
[ 'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.', {withoutStack: true},
{withoutStack: true}, ],
], ]);
]);
} else {
assertConsoleErrorDev([
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.' +
'\n in Suspense (at **)' +
'\n in html (at **)' +
'\n in App (at **)',
'In HTML, <meta> cannot be a child of <html>.\nThis will cause a hydration error.' +
'\n' +
'\n <App>' +
'\n> <html>' +
'\n <Suspense fallback="this fallb...">' +
'\n <meta>' +
'\n> <meta itemProp="" content="before">' +
'\n ...' +
'\n' +
'\n in meta (at **)' +
'\n in Suspense (at **)' +
'\n in html (at **)' +
'\n in App (at **)',
'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.' +
'\n in Suspense (at **)' +
'\n in html (at **)' +
'\n in App (at **)',
]);
}
await root.unmount(); await root.unmount();
expect(getVisibleChildren(document)).toEqual( expect(getVisibleChildren(document)).toEqual(

View File

@ -529,8 +529,7 @@ describe('ReactDOMFloat', () => {
'> <template>\n' + '> <template>\n' +
' ...\n' + ' ...\n' +
'\n' + '\n' +
' in template (at **)' + ' in template (at **)',
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
]); ]);
root.render( root.render(
@ -555,8 +554,7 @@ describe('ReactDOMFloat', () => {
' <body>\n' + ' <body>\n' +
'> <style>\n' + '> <style>\n' +
'\n' + '\n' +
' in style (at **)' + ' in style (at **)',
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
]); ]);
root.render( root.render(
@ -596,8 +594,7 @@ describe('ReactDOMFloat', () => {
' <body>\n' + ' <body>\n' +
'> <script href="foo">\n' + '> <script href="foo">\n' +
'\n' + '\n' +
' in script (at **)' + ' in script (at **)',
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
]); ]);
root.render( root.render(
@ -2269,21 +2266,11 @@ body {
'spell it as lowercase `nonstandardattr` instead. If you accidentally passed it from a ' + 'spell it as lowercase `nonstandardattr` instead. If you accidentally passed it from a ' +
'parent component, remove it from the DOM element.\n' + 'parent component, remove it from the DOM element.\n' +
' in link (at **)\n' + ' in link (at **)\n' +
(gate('enableOwnerStacks')
? ''
: ' in div (at **)\n' +
' in body (at **)\n' +
' in html (at **)\n') +
' in App (at **)', ' in App (at **)',
'Invalid values for props `shouldnotincludefunctions`, `norsymbols` on <link> tag. ' + 'Invalid values for props `shouldnotincludefunctions`, `norsymbols` on <link> tag. ' +
'Either remove them from the element, or pass a string or number value to keep them in the DOM. ' + 'Either remove them from the element, or pass a string or number value to keep them in the DOM. ' +
'For details, see https://react.dev/link/attribute-behavior \n' + 'For details, see https://react.dev/link/attribute-behavior \n' +
' in link (at **)\n' + ' in link (at **)\n' +
(gate('enableOwnerStacks')
? ''
: ' in div (at **)\n' +
' in body (at **)\n' +
' in html (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
@ -2642,8 +2629,7 @@ body {
'> <html>\n' + '> <html>\n' +
'> <meta itemProp="foo">' + '> <meta itemProp="foo">' +
'\n' + '\n' +
'\n in meta (at **)' + '\n in meta (at **)',
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
]); ]);
}); });
@ -2668,8 +2654,7 @@ body {
'> <html>\n' + '> <html>\n' +
'> <title itemProp="foo">' + '> <title itemProp="foo">' +
'\n' + '\n' +
'\n in title (at **)' + '\n in title (at **)',
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
]); ]);
}); });
@ -2694,8 +2679,7 @@ body {
'> <html>\n' + '> <html>\n' +
'> <style itemProp="foo">' + '> <style itemProp="foo">' +
'\n' + '\n' +
'\n in style (at **)' + '\n in style (at **)',
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
]); ]);
}); });
@ -2720,8 +2704,7 @@ body {
'> <html>\n' + '> <html>\n' +
'> <link itemProp="foo">\n' + '> <link itemProp="foo">\n' +
'\n' + '\n' +
' in link (at **)' + ' in link (at **)',
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
]); ]);
}); });
@ -2746,8 +2729,7 @@ body {
'> <html>\n' + '> <html>\n' +
'> <script itemProp="foo">\n' + '> <script itemProp="foo">\n' +
'\n' + '\n' +
' in script (at **)' + ' in script (at **)',
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
]); ]);
}); });
@ -4844,9 +4826,6 @@ body {
'React encountered a hoistable style tag for the same href as a preload: "foo". ' + 'React encountered a hoistable style tag for the same href as a preload: "foo". ' +
'When using a style tag to inline styles you should not also preload it as a stylsheet.\n' + 'When using a style tag to inline styles you should not also preload it as a stylsheet.\n' +
' in style (at **)\n' + ' in style (at **)\n' +
(gate('enableOwnerStacks')
? ''
: ' in body (at **)\n' + ' in html (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
@ -7753,64 +7732,43 @@ body {
'If your intent was to have React hoist and deduplciate this stylesheet using the ' + 'If your intent was to have React hoist and deduplciate this stylesheet using the ' +
'`precedence` prop ensure there is a non-empty string `href` prop as well, ' + '`precedence` prop ensure there is a non-empty string `href` prop as well, ' +
'otherwise remove the `precedence` prop.\n' + 'otherwise remove the `precedence` prop.\n' +
' in link (at **)' + ' in link (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and ' + 'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and ' +
'expected the `href` prop to be a non-empty string but ecountered an empty string instead. ' + 'expected the `href` prop to be a non-empty string but ecountered an empty string instead. ' +
'If your intent was to have React hoist and deduplciate this stylesheet using the ' + 'If your intent was to have React hoist and deduplciate this stylesheet using the ' +
'`precedence` prop ensure there is a non-empty string `href` prop as well, ' + '`precedence` prop ensure there is a non-empty string `href` prop as well, ' +
'otherwise remove the `precedence` prop.\n' + 'otherwise remove the `precedence` prop.\n' +
' in link (at **)' + ' in link (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
'An empty string ("") was passed to the href attribute. ' + 'An empty string ("") was passed to the href attribute. ' +
'To fix this, either do not render the element at all or ' + 'To fix this, either do not render the element at all or ' +
'pass null to href instead of an empty string.\n' + 'pass null to href instead of an empty string.\n' +
' in link (at **)' + ' in link (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and ' + 'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and ' +
'`onLoad` and `onError` props. The presence of loading and error handlers indicates ' + '`onLoad` and `onError` props. The presence of loading and error handlers indicates ' +
'an intent to manage the stylesheet loading state from your from your Component code ' + 'an intent to manage the stylesheet loading state from your from your Component code ' +
'and React will not hoist or deduplicate this stylesheet. ' + 'and React will not hoist or deduplicate this stylesheet. ' +
'If your intent was to have React hoist and deduplciate this stylesheet using the ' + 'If your intent was to have React hoist and deduplciate this stylesheet using the ' +
'`precedence` prop remove the `onLoad` and `onError` props, otherwise remove the `precedence` prop.\n' + '`precedence` prop remove the `onLoad` and `onError` props, otherwise remove the `precedence` prop.\n' +
' in link (at **)' + ' in link (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and ' + 'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and ' +
'`onLoad` prop. The presence of loading and error handlers indicates an intent to ' + '`onLoad` prop. The presence of loading and error handlers indicates an intent to ' +
'manage the stylesheet loading state from your from your Component code and ' + 'manage the stylesheet loading state from your from your Component code and ' +
'React will not hoist or deduplicate this stylesheet. ' + 'React will not hoist or deduplicate this stylesheet. ' +
'If your intent was to have React hoist and deduplciate this stylesheet using the ' + 'If your intent was to have React hoist and deduplciate this stylesheet using the ' +
'`precedence` prop remove the `onLoad` prop, otherwise remove the `precedence` prop.\n' + '`precedence` prop remove the `onLoad` prop, otherwise remove the `precedence` prop.\n' +
' in link (at **)' + ' in link (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and `onError` prop. ' + 'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and `onError` prop. ' +
'The presence of loading and error handlers indicates an intent to manage the stylesheet loading state ' + 'The presence of loading and error handlers indicates an intent to manage the stylesheet loading state ' +
'from your from your Component code and React will not hoist or deduplicate this stylesheet. ' + 'from your from your Component code and React will not hoist or deduplicate this stylesheet. ' +
'If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` ' + 'If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` ' +
'prop remove the `onError` prop, otherwise remove the `precedence` prop.\n' + 'prop remove the `onError` prop, otherwise remove the `precedence` prop.\n' +
' in link (at **)' + ' in link (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and a `disabled` prop. ' + 'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and a `disabled` prop. ' +
'The presence of the `disabled` prop indicates an intent to manage the stylesheet active state from ' + 'The presence of the `disabled` prop indicates an intent to manage the stylesheet active state from ' +
'your from your Component code and React will not hoist or deduplicate this stylesheet. ' + 'your from your Component code and React will not hoist or deduplicate this stylesheet. ' +
'If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` ' + 'If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` ' +
'prop remove the `disabled` prop, otherwise remove the `precedence` prop.\n' + 'prop remove the `disabled` prop, otherwise remove the `precedence` prop.\n' +
' in link (at **)' + ' in link (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
].filter(Boolean), ].filter(Boolean),
); );
@ -7836,8 +7794,7 @@ body {
'loading state from your from your Component code and React will not hoist or deduplicate this stylesheet. ' + 'loading state from your from your Component code and React will not hoist or deduplicate this stylesheet. ' +
'If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` ' + 'If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` ' +
'prop remove the `onLoad` and `onError` props, otherwise remove the `precedence` prop.\n' + 'prop remove the `onLoad` and `onError` props, otherwise remove the `precedence` prop.\n' +
' in body (at **)' + ' in body (at **)',
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
]); ]);
}); });
@ -8429,10 +8386,7 @@ background-color: green;
'using the `precedence` prop to not have any spaces but ecountered spaces instead. ' + 'using the `precedence` prop to not have any spaces but ecountered spaces instead. ' +
'using spaces in this prop will cause hydration of this style to fail on the client. ' + 'using spaces in this prop will cause hydration of this style to fail on the client. ' +
'The href for the <style> where this ocurred is "foo bar".\n' + 'The href for the <style> where this ocurred is "foo bar".\n' +
' in style (at **)' + ' in style (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
]); ]);
}); });
}); });

View File

@ -391,8 +391,7 @@ describe('ReactDOMForm', () => {
'> <form action={function outerAction}>\n' + '> <form action={function outerAction}>\n' +
' <input>\n' + ' <input>\n' +
'> <form action={function innerAction} ref={{current:null}}>\n' + '> <form action={function innerAction} ref={{current:null}}>\n' +
'\n in form (at **)' + '\n in form (at **)',
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in form (at **)'),
]); ]);
await submit(ref.current); await submit(ref.current);
@ -588,8 +587,7 @@ describe('ReactDOMForm', () => {
'Cannot specify a "name" prop for a button that specifies a function as a formAction. ' + 'Cannot specify a "name" prop for a button that specifies a function as a formAction. ' +
'React needs it to encode which action should be invoked. ' + 'React needs it to encode which action should be invoked. ' +
'It will get overridden.\n' + 'It will get overridden.\n' +
' in input (at **)' + ' in input (at **)',
(gate('enableOwnerStacks') ? '' : '\n in form (at **)'),
]); ]);
await submit(inputRef.current); await submit(inputRef.current);
@ -1971,7 +1969,6 @@ describe('ReactDOMForm', () => {
'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' + 'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' +
'For details, see https://react.dev/link/attribute-behavior \n' + 'For details, see https://react.dev/link/attribute-behavior \n' +
' in button (at **)\n' + ' in button (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in form (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
await submit(buttonRef.current); await submit(buttonRef.current);

View File

@ -59,10 +59,7 @@ describe('ReactDOMOption', () => {
'> <div>\n' + '> <div>\n' +
' ...\n' + ' ...\n' +
'\n' + '\n' +
' in div (at **)' + ' in div (at **)',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in option (at **)'),
]); ]);
expect(container.firstChild.innerHTML).toBe('1 <div></div> 2'); expect(container.firstChild.innerHTML).toBe('1 <div></div> 2');
await renderIntoDocument(el); await renderIntoDocument(el);
@ -279,10 +276,7 @@ describe('ReactDOMOption', () => {
'> <div ref={{current:null}}>\n' + '> <div ref={{current:null}}>\n' +
' ...\n' + ' ...\n' +
'\n' + '\n' +
' in div (at **)' + ' in div (at **)',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in option (at **)' + '\n in select (at **)'),
]); ]);
option = container.firstChild.firstChild; option = container.firstChild.firstChild;

View File

@ -794,7 +794,6 @@ describe('ReactDOMSelect', () => {
'Use the `defaultValue` or `value` props on <select> instead of ' + 'Use the `defaultValue` or `value` props on <select> instead of ' +
'setting `selected` on <option>.\n' + 'setting `selected` on <option>.\n' +
' in option (at **)\n' + ' in option (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in select (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
@ -1072,8 +1071,7 @@ describe('ReactDOMSelect', () => {
'Invalid value for prop `value` on <option> tag. ' + 'Invalid value for prop `value` on <option> tag. ' +
'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' + 'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' +
'For details, see https://react.dev/link/attribute-behavior \n' + 'For details, see https://react.dev/link/attribute-behavior \n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
const node = container.firstChild; const node = container.firstChild;
@ -1096,8 +1094,7 @@ describe('ReactDOMSelect', () => {
'Invalid value for prop `value` on <option> tag. ' + 'Invalid value for prop `value` on <option> tag. ' +
'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' + 'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' +
'For details, see https://react.dev/link/attribute-behavior \n' + 'For details, see https://react.dev/link/attribute-behavior \n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
let node = container.firstChild; let node = container.firstChild;
@ -1134,8 +1131,7 @@ describe('ReactDOMSelect', () => {
'Invalid value for prop `value` on <option> tag. ' + 'Invalid value for prop `value` on <option> tag. ' +
'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' + 'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' +
'For details, see https://react.dev/link/attribute-behavior \n' + 'For details, see https://react.dev/link/attribute-behavior \n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
const node = container.firstChild; const node = container.firstChild;
@ -1158,8 +1154,7 @@ describe('ReactDOMSelect', () => {
'Invalid value for prop `value` on <option> tag. ' + 'Invalid value for prop `value` on <option> tag. ' +
'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' + 'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' +
'For details, see https://react.dev/link/attribute-behavior \n' + 'For details, see https://react.dev/link/attribute-behavior \n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
let node = container.firstChild; let node = container.firstChild;
@ -1199,8 +1194,7 @@ describe('ReactDOMSelect', () => {
'Invalid value for prop `value` on <option> tag. ' + 'Invalid value for prop `value` on <option> tag. ' +
'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' + 'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' +
'For details, see https://react.dev/link/attribute-behavior \n' + 'For details, see https://react.dev/link/attribute-behavior \n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
const node = container.firstChild; const node = container.firstChild;
@ -1223,8 +1217,7 @@ describe('ReactDOMSelect', () => {
'Invalid value for prop `value` on <option> tag. ' + 'Invalid value for prop `value` on <option> tag. ' +
'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' + 'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' +
'For details, see https://react.dev/link/attribute-behavior \n' + 'For details, see https://react.dev/link/attribute-behavior \n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
const node = container.firstChild; const node = container.firstChild;
@ -1247,8 +1240,7 @@ describe('ReactDOMSelect', () => {
'Invalid value for prop `value` on <option> tag. ' + 'Invalid value for prop `value` on <option> tag. ' +
'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' + 'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' +
'For details, see https://react.dev/link/attribute-behavior \n' + 'For details, see https://react.dev/link/attribute-behavior \n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
let node = container.firstChild; let node = container.firstChild;
@ -1284,8 +1276,7 @@ describe('ReactDOMSelect', () => {
'Invalid value for prop `value` on <option> tag. ' + 'Invalid value for prop `value` on <option> tag. ' +
'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' + 'Either remove it from the element, or pass a string or number value to keep it in the DOM. ' +
'For details, see https://react.dev/link/attribute-behavior \n' + 'For details, see https://react.dev/link/attribute-behavior \n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
let node = container.firstChild; let node = container.firstChild;
@ -1366,12 +1357,10 @@ describe('ReactDOMSelect', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
}); });
@ -1395,12 +1384,10 @@ describe('ReactDOMSelect', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
}); });
@ -1467,8 +1454,7 @@ describe('ReactDOMSelect', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
}); });
@ -1508,8 +1494,7 @@ describe('ReactDOMSelect', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
'Form field values (value, checked, defaultValue, or defaultChecked props)' + 'Form field values (value, checked, defaultValue, or defaultChecked props)' +
' must be strings, not TemporalLike. ' + ' must be strings, not TemporalLike. ' +
'This value must be coerced to a string before using it here.\n' + 'This value must be coerced to a string before using it here.\n' +
@ -1563,12 +1548,10 @@ describe('ReactDOMSelect', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
}); });
@ -1591,12 +1574,10 @@ describe('ReactDOMSelect', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
}); });
@ -1670,12 +1651,10 @@ describe('ReactDOMSelect', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
'The provided `value` attribute is an unsupported type TemporalLike.' + 'The provided `value` attribute is an unsupported type TemporalLike.' +
' This value must be coerced to a string before using it here.\n' + ' This value must be coerced to a string before using it here.\n' +
' in option (at **)' + ' in option (at **)',
(gate('enableOwnerStacks') ? '' : '\n in select (at **)'),
]); ]);
}); });

View File

@ -995,18 +995,6 @@ describe('ReactDOMServerIntegration', () => {
async render => { async render => {
let EmptyComponent = {}; let EmptyComponent = {};
EmptyComponent = <EmptyComponent />; EmptyComponent = <EmptyComponent />;
assertConsoleErrorDev(
gate(flags => flags.enableOwnerStacks)
? []
: [
'React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: object. You likely forgot to export your ' +
"component from the file it's defined in, or you might have mixed up " +
'default and named imports.',
],
{withoutStack: true},
);
await render(EmptyComponent); await render(EmptyComponent);
}, },
'Element type is invalid: expected a string (for built-in components) or a class/function ' + 'Element type is invalid: expected a string (for built-in components) or a class/function ' +
@ -1022,16 +1010,6 @@ describe('ReactDOMServerIntegration', () => {
async render => { async render => {
let NullComponent = null; let NullComponent = null;
NullComponent = <NullComponent />; NullComponent = <NullComponent />;
assertConsoleErrorDev(
gate(flags => flags.enableOwnerStacks)
? []
: [
'React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: null.',
],
{withoutStack: true},
);
await render(NullComponent); await render(NullComponent);
}, },
'Element type is invalid: expected a string (for built-in components) or a class/function ' + 'Element type is invalid: expected a string (for built-in components) or a class/function ' +
@ -1043,19 +1021,6 @@ describe('ReactDOMServerIntegration', () => {
async render => { async render => {
let UndefinedComponent = undefined; let UndefinedComponent = undefined;
UndefinedComponent = <UndefinedComponent />; UndefinedComponent = <UndefinedComponent />;
assertConsoleErrorDev(
gate(flags => flags.enableOwnerStacks)
? []
: [
'React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' +
"component from the file it's defined in, or you might have mixed up " +
'default and named imports.',
],
{withoutStack: true},
);
await render(UndefinedComponent); await render(UndefinedComponent);
}, },
'Element type is invalid: expected a string (for built-in components) or a class/function ' + 'Element type is invalid: expected a string (for built-in components) or a class/function ' +

View File

@ -286,7 +286,6 @@ describe('ReactDOMServerLifecycles', () => {
'usually means you called setState() outside componentWillMount() on ' + 'usually means you called setState() outside componentWillMount() on ' +
'the server. This is a no-op.\n\n' + 'the server. This is a no-op.\n\n' +
'Please check the code for the Outer component.\n' + 'Please check the code for the Outer component.\n' +
(gate('enableOwnerStacks') ? '' : ' in Inner (at **)\n') +
' in Outer (at **)', ' in Outer (at **)',
]); ]);
}); });

View File

@ -1923,11 +1923,6 @@ describe('ReactDOMServerPartialHydration', () => {
"Can't perform a React state update on a component that hasn't mounted yet. " + "Can't perform a React state update on a component that hasn't mounted yet. " +
'This indicates that you have a side-effect in your render function that ' + 'This indicates that you have a side-effect in your render function that ' +
'asynchronously later calls tries to update the component. Move this work to useEffect instead.\n' + 'asynchronously later calls tries to update the component. Move this work to useEffect instead.\n' +
(gate('enableOwnerStacks')
? ''
: ' in Child (at **)\n' +
' in Suspense (at **)\n' +
' in div (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);

View File

@ -171,8 +171,7 @@ describe('ReactDOM HostSingleton', () => {
'children of these components will likely fail in unpredictable ways. ' + 'children of these components will likely fail in unpredictable ways. ' +
'Please only render a single instance of <head> and if you need to mount a new one, ' + 'Please only render a single instance of <head> and if you need to mount a new one, ' +
'ensure any previous ones have unmounted first.\n' + 'ensure any previous ones have unmounted first.\n' +
' in head (at **)' + ' in head (at **)',
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
]); ]);
expect(getVisibleChildren(document)).toEqual( expect(getVisibleChildren(document)).toEqual(
<html> <html>

View File

@ -60,11 +60,13 @@ describe('ReactDeprecationWarnings', () => {
</div>, </div>,
); );
await waitForAll([]); await waitForAll([]);
assertConsoleErrorDev([ assertConsoleErrorDev(
'FunctionalComponent: Support for defaultProps ' + [
'will be removed from memo components in a future major ' + 'FunctionalComponent: Support for defaultProps ' +
'release. Use JavaScript default parameters instead.\n' + 'will be removed from memo components in a future major ' +
' in div (at **)', 'release. Use JavaScript default parameters instead.',
]); ],
{withoutStack: true},
);
}); });
}); });

View File

@ -2381,17 +2381,6 @@ describe('ReactErrorBoundaries', () => {
'class/function (for composite components) but got: null.', 'class/function (for composite components) but got: null.',
); );
if (!gate('enableOwnerStacks')) {
assertConsoleErrorDev(
[
'React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function ' +
'(for composite components) but got: null.',
],
{withoutStack: true},
);
}
await expect(async () => { await expect(async () => {
const container = document.createElement('div'); const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container); const root = ReactDOMClient.createRoot(container);
@ -2403,18 +2392,6 @@ describe('ReactErrorBoundaries', () => {
'expected a string (for built-in components) or a ' + 'expected a string (for built-in components) or a ' +
'class/function (for composite components) but got: undefined.', 'class/function (for composite components) but got: undefined.',
); );
if (!gate('enableOwnerStacks')) {
assertConsoleErrorDev(
[
'React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function ' +
'(for composite components) but got: undefined. ' +
"You likely forgot to export your component from the file it's defined in, " +
'or you might have mixed up default and named imports.',
],
{withoutStack: true},
);
}
}); });
it('renders empty output if error boundary does not handle the error', async () => { it('renders empty output if error boundary does not handle the error', async () => {

View File

@ -116,7 +116,6 @@ describe('ReactFunctionComponent', () => {
' in GrandParent (at **)', ' in GrandParent (at **)',
'Child uses the legacy contextTypes API which will soon be removed. ' + 'Child uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in Child (at **)\n') +
' in Parent (at **)\n' + ' in Parent (at **)\n' +
' in GrandParent (at **)', ' in GrandParent (at **)',
]); ]);
@ -260,7 +259,6 @@ describe('ReactFunctionComponent', () => {
' in Parent (at **)', ' in Parent (at **)',
'Child uses the legacy contextTypes API which will be removed soon. ' + 'Child uses the legacy contextTypes API which will be removed soon. ' +
'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
' in Child (at **)\n' +
' in Parent (at **)', ' in Parent (at **)',
]); ]);
expect(el.textContent).toBe('en'); expect(el.textContent).toBe('en');

View File

@ -121,13 +121,9 @@ describe('ReactLegacyCompositeComponent', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'Child uses the legacy childContextTypes API which will soon be removed. ' + 'Child uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in Child (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
'Grandchild uses the legacy contextTypes API which will soon be removed. ' + 'Grandchild uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks')
? ''
: ' in Grandchild (at **)\n' + ' in Child (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
]); ]);
expect(findDOMNode(component).innerHTML).toBe('bar'); expect(findDOMNode(component).innerHTML).toBe('bar');
@ -200,10 +196,7 @@ describe('ReactLegacyCompositeComponent', () => {
' in Parent (at **)', ' in Parent (at **)',
'Child uses the legacy contextTypes API which will soon be removed. ' + 'Child uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in Child (at **)' + ' in Child (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in Middle (at **)' + '\n in Parent (at **)'),
]); ]);
await act(() => { await act(() => {
@ -268,15 +261,9 @@ describe('ReactLegacyCompositeComponent', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'Parent uses the legacy childContextTypes API which will soon be removed. ' + 'Parent uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in Parent (at **)\n') +
' in Wrapper (at **)', ' in Wrapper (at **)',
'Child uses the legacy contextTypes API which will soon be removed. ' + 'Child uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks')
? ''
: ' in Child (at **)\n' +
' in div (at **)\n' +
' in Parent (at **)\n') +
' in Wrapper (at **)', ' in Wrapper (at **)',
]); ]);
@ -361,15 +348,12 @@ describe('ReactLegacyCompositeComponent', () => {
' in Parent (at **)', ' in Parent (at **)',
'Child uses the legacy childContextTypes API which will soon be removed. ' + 'Child uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in Child (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
'Child uses the legacy contextTypes API which will soon be removed. ' + 'Child uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in Child (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
'Grandchild uses the legacy contextTypes API which will soon be removed. ' + 'Grandchild uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in Grandchild (at **)\n') +
' in Child (at **)\n' + ' in Child (at **)\n' +
' in Parent (at **)', ' in Parent (at **)',
]); ]);
@ -441,7 +425,6 @@ describe('ReactLegacyCompositeComponent', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'Child uses the legacy contextTypes API which will soon be removed. ' + 'Child uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in Child (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
]); ]);

View File

@ -104,16 +104,10 @@ describe('ReactLegacyContextDisabled', () => {
' in LegacyProvider (at **)', ' in LegacyProvider (at **)',
'LegacyClsConsumer uses the legacy contextTypes API which was removed in React 19. ' + 'LegacyClsConsumer uses the legacy contextTypes API which was removed in React 19. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in LegacyClsConsumer (at **)' + ' in LegacyClsConsumer (at **)',
(gate('enableOwnerStacks')
? ''
: '\n' + ' in span (at **)\n' + ' in LegacyProvider (at **)'),
'LegacyFnConsumer uses the legacy contextTypes API which was removed in React 19. ' + 'LegacyFnConsumer uses the legacy contextTypes API which was removed in React 19. ' +
'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
' in LegacyFnConsumer (at **)' + ' in LegacyFnConsumer (at **)',
(gate('enableOwnerStacks')
? ''
: '\n' + ' in span (at **)\n' + ' in LegacyProvider (at **)'),
]); ]);
expect(container.textContent).toBe('{}undefinedundefined'); expect(container.textContent).toBe('{}undefinedundefined');
expect(lifecycleContextLog).toEqual([]); expect(lifecycleContextLog).toEqual([]);
@ -151,16 +145,10 @@ describe('ReactLegacyContextDisabled', () => {
' in LegacyProvider (at **)', ' in LegacyProvider (at **)',
'LegacyClsConsumer uses the legacy contextTypes API which was removed in React 19. ' + 'LegacyClsConsumer uses the legacy contextTypes API which was removed in React 19. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in LegacyClsConsumer (at **)' + ' in LegacyClsConsumer (at **)',
(gate('enableOwnerStacks')
? ''
: '\n' + ' in span (at **)\n' + ' in LegacyProvider (at **)'),
'LegacyFnConsumer uses the legacy contextTypes API which was removed in React 19. ' + 'LegacyFnConsumer uses the legacy contextTypes API which was removed in React 19. ' +
'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
' in LegacyFnConsumer (at **)' + ' in LegacyFnConsumer (at **)',
(gate('enableOwnerStacks')
? ''
: '\n' + ' in span (at **)\n' + ' in LegacyProvider (at **)'),
]); ]);
expect(text).toBe('<span>{}<!-- -->undefined<!-- -->undefined</span>'); expect(text).toBe('<span>{}<!-- -->undefined<!-- -->undefined</span>');
expect(lifecycleContextLog).toEqual([{}, {}, {}]); expect(lifecycleContextLog).toEqual([{}, {}, {}]);

View File

@ -2112,16 +2112,6 @@ describe('ReactLegacyErrorBoundaries', () => {
ReactDOM.render(<X />, container); ReactDOM.render(<X />, container);
}); });
}).rejects.toThrow('got: null'); }).rejects.toThrow('got: null');
if (gate(flags => !flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function ' +
'(for composite components) but got: null.',
],
{withoutStack: true},
);
}
await expect(async () => { await expect(async () => {
const container = document.createElement('div'); const container = document.createElement('div');
@ -2129,16 +2119,6 @@ describe('ReactLegacyErrorBoundaries', () => {
ReactDOM.render(<Y />, container); ReactDOM.render(<Y />, container);
}); });
}).rejects.toThrow('got: undefined'); }).rejects.toThrow('got: undefined');
if (gate(flags => !flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function ' +
'(for composite components) but got: undefined.',
],
{withoutStack: true},
);
}
}); });
// @gate !disableLegacyMode // @gate !disableLegacyMode

View File

@ -228,13 +228,7 @@ describe('ReactMultiChild', () => {
'across updates. Non-unique keys may cause children to be ' + 'across updates. Non-unique keys may cause children to be ' +
'duplicated and/or omitted — the behavior is unsupported and ' + 'duplicated and/or omitted — the behavior is unsupported and ' +
'could change in a future version.\n' + 'could change in a future version.\n' +
' in div (at **)' + ' in div (at **)',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in div (at **)' +
'\n in WrapperComponent (at **)' +
'\n in div (at **)' +
'\n in Parent (at **)'),
]); ]);
}); });
@ -290,13 +284,7 @@ describe('ReactMultiChild', () => {
'across updates. Non-unique keys may cause children to be ' + 'across updates. Non-unique keys may cause children to be ' +
'duplicated and/or omitted — the behavior is unsupported and ' + 'duplicated and/or omitted — the behavior is unsupported and ' +
'could change in a future version.\n' + 'could change in a future version.\n' +
' in div (at **)' + ' in div (at **)',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in div (at **)' +
'\n in WrapperComponent (at **)' +
'\n in div (at **)' +
'\n in Parent (at **)'),
]); ]);
}); });
}); });

View File

@ -758,20 +758,12 @@ describe('ReactDOMServer', () => {
'<inPUT /> is using incorrect casing. ' + '<inPUT /> is using incorrect casing. ' +
'Use PascalCase for React components, ' + 'Use PascalCase for React components, ' +
'or lowercase for HTML elements.\n' + 'or lowercase for HTML elements.\n' +
' in inPUT (at **)' + ' in inPUT (at **)',
(gate('enableOwnerStacks') ? '' : '\n in div (at **)'),
// linearGradient doesn't warn // linearGradient doesn't warn
'<iFrame /> is using incorrect casing. ' + '<iFrame /> is using incorrect casing. ' +
'Use PascalCase for React components, ' + 'Use PascalCase for React components, ' +
'or lowercase for HTML elements.\n' + 'or lowercase for HTML elements.\n' +
' in iFrame (at **)' + ' in iFrame (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in foreignObject (at **)' +
'\n in g (at **)' +
'\n in CompositeG (at **)' +
'\n in svg (at **)' +
'\n in div (at **)'),
]); ]);
}); });
@ -869,30 +861,14 @@ describe('ReactDOMServer', () => {
ReactDOMServer.renderToString(<App />); ReactDOMServer.renderToString(<App />);
assertConsoleErrorDev([ assertConsoleErrorDev([
'Invalid ARIA attribute `ariaTypo`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + 'Invalid ARIA attribute `ariaTypo`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
(gate(flags => flags.enableOwnerStacks) ' in span (at **)\n' +
? ' in span (at **)\n' + ' in B (at **)\n' +
' in B (at **)\n' + ' in Child (at **)\n' +
' in Child (at **)\n' + ' in App (at **)',
' in App (at **)'
: ' in span (at **)\n' +
' in b (at **)\n' +
' in C (at **)\n' +
' in font (at **)\n' +
' in B (at **)\n' +
' in Child (at **)\n' +
' in span (at **)\n' +
' in div (at **)\n' +
' in App (at **)'),
'Invalid ARIA attribute `ariaTypo2`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + 'Invalid ARIA attribute `ariaTypo2`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
(gate(flags => flags.enableOwnerStacks) ' in span (at **)\n' +
? ' in span (at **)\n' + ' in Child (at **)\n' +
' in Child (at **)\n' + ' in App (at **)',
' in App (at **)'
: ' in span (at **)\n' +
' in Child (at **)\n' +
' in span (at **)\n' +
' in div (at **)\n' +
' in App (at **)'),
]); ]);
}); });
@ -929,47 +905,30 @@ describe('ReactDOMServer', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
// ReactDOMServer(App > div > span) // ReactDOMServer(App > div > span)
'Invalid ARIA attribute `ariaTypo`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + 'Invalid ARIA attribute `ariaTypo`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
(gate(flags => flags.enableOwnerStacks) ' in span (at **)\n' +
? ' in span (at **)\n' + ' in App (at **)' ' in App (at **)',
: ' in span (at **)\n' +
' in div (at **)\n' +
' in App (at **)'),
// ReactDOMServer(App > div > Child) >>> ReactDOMServer(App2) >>> ReactDOMServer(blink) // ReactDOMServer(App > div > Child) >>> ReactDOMServer(App2) >>> ReactDOMServer(blink)
'Invalid ARIA attribute `ariaTypo2`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + 'Invalid ARIA attribute `ariaTypo2`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
(gate(flags => flags.enableOwnerStacks) ' in blink (at **)\n' +
? ' in blink (at **)\n' + ' in App2 (at **)\n' +
' in App2 (at **)\n' + ' in Child (at **)\n' +
' in Child (at **)\n' + ' in App (at **)',
' in App (at **)'
: ' in blink (at **)'),
// ReactDOMServer(App > div > Child) >>> ReactDOMServer(App2 > Child2 > span) // ReactDOMServer(App > div > Child) >>> ReactDOMServer(App2 > Child2 > span)
'Invalid ARIA attribute `ariaTypo3`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + 'Invalid ARIA attribute `ariaTypo3`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
(gate(flags => flags.enableOwnerStacks) ' in span (at **)\n' +
? ' in span (at **)\n' + ' in Child2 (at **)\n' +
' in Child2 (at **)\n' + ' in App2 (at **)\n' +
' in App2 (at **)\n' + ' in Child (at **)\n' +
' in Child (at **)\n' + ' in App (at **)',
' in App (at **)'
: ' in span (at **)\n' +
' in Child2 (at **)\n' +
' in App2 (at **)'),
// ReactDOMServer(App > div > Child > span) // ReactDOMServer(App > div > Child > span)
'Invalid ARIA attribute `ariaTypo4`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + 'Invalid ARIA attribute `ariaTypo4`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
(gate(flags => flags.enableOwnerStacks) ' in span (at **)\n' +
? ' in span (at **)\n' + ' in Child (at **)\n' +
' in Child (at **)\n' + ' in App (at **)',
' in App (at **)'
: ' in span (at **)\n' +
' in Child (at **)\n' +
' in div (at **)\n' +
' in App (at **)'),
// ReactDOMServer(App > div > font) // ReactDOMServer(App > div > font)
'Invalid ARIA attribute `ariaTypo5`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + 'Invalid ARIA attribute `ariaTypo5`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' +
(gate(flags => flags.enableOwnerStacks) ' in font (at **)\n' +
? ' in font (at **)\n' + ' in App (at **)' ' in App (at **)',
: ' in font (at **)\n' +
' in div (at **)\n' +
' in App (at **)'),
]); ]);
}); });

View File

@ -1877,9 +1877,7 @@ describe('ReactUpdates', () => {
const originalConsoleError = console.error; const originalConsoleError = console.error;
console.error = e => { console.error = e => {
error = e; error = e;
ownerStack = gate(flags => flags.enableOwnerStacks) ownerStack = React.captureOwnerStack();
? React.captureOwnerStack()
: null;
debugStack = new Error().stack; debugStack = new Error().stack;
Scheduler.log('stop'); Scheduler.log('stop');
}; };
@ -1895,11 +1893,7 @@ describe('ReactUpdates', () => {
expect(error).toContain('Maximum update depth exceeded'); expect(error).toContain('Maximum update depth exceeded');
// The currently executing effect should be on the native stack // The currently executing effect should be on the native stack
expect(debugStack).toContain('at myEffect'); expect(debugStack).toContain('at myEffect');
if (gate(flags => flags.enableOwnerStacks)) { expect(ownerStack).toContain('at App');
expect(ownerStack).toContain('at App');
} else {
expect(ownerStack).toBe(null);
}
}); });
it('can have nested updates if they do not cross the limit', async () => { it('can have nested updates if they do not cross the limit', async () => {

View File

@ -121,34 +121,20 @@ describe('validateDOMNesting', () => {
); );
expectWarnings( expectWarnings(
['div', 'ul', 'li', 'div', 'li'], ['div', 'ul', 'li', 'div', 'li'],
gate(flags => flags.enableOwnerStacks)
? [ [
'In HTML, <li> cannot be a descendant of <li>.\n' + 'In HTML, <li> cannot be a descendant of <li>.\n' +
'This will cause a hydration error.\n' + 'This will cause a hydration error.\n' +
'\n' + '\n' +
' <ul>\n' + ' <ul>\n' +
'> <li>\n' + '> <li>\n' +
' <div>\n' + ' <div>\n' +
'> <li>\n' + '> <li>\n' +
'\n' + '\n' +
' in li (at **)', ' in li (at **)',
'<li> cannot contain a nested <li>.\nSee this log for the ancestor stack trace.\n' + '<li> cannot contain a nested <li>.\nSee this log for the ancestor stack trace.\n' +
' in li (at **)', ' in li (at **)',
] ],
: [
'In HTML, <li> cannot be a descendant of <li>.\n' +
'This will cause a hydration error.\n' +
'\n' +
' <ul>\n' +
'> <li>\n' +
' <div>\n' +
'> <li>\n' +
'\n' +
' in li (at **)\n' +
' in div (at **)\n' +
' in li (at **)\n' +
' in ul (at **)',
],
); );
expectWarnings( expectWarnings(
['div', 'html'], ['div', 'html'],
@ -208,28 +194,16 @@ describe('validateDOMNesting', () => {
); );
expectWarnings( expectWarnings(
['svg', 'foreignObject', 'body', 'p'], ['svg', 'foreignObject', 'body', 'p'],
gate(flags => flags.enableOwnerStacks) [
? [ // TODO, this should say "In SVG",
// TODO, this should say "In SVG", 'In HTML, <body> cannot be a child of <foreignObject>.\n' +
'In HTML, <body> cannot be a child of <foreignObject>.\n' + 'This will cause a hydration error.\n' +
'This will cause a hydration error.\n' + '\n' +
'\n' + '> <foreignObject>\n' +
'> <foreignObject>\n' + '> <body>\n' +
'> <body>\n' + '\n' +
'\n' + ' in body (at **)',
' in body (at **)', ],
]
: [
// TODO, this should say "In SVG",
'In HTML, <body> cannot be a child of <foreignObject>.\n' +
'This will cause a hydration error.\n' +
'\n' +
'> <foreignObject>\n' +
'> <body>\n' +
'\n' +
' in body (at **)\n' +
' in foreignObject (at **)',
],
); );
}); });

View File

@ -233,9 +233,7 @@ if (!__EXPERIMENTAL__) {
'\n in div (at **)', '\n in div (at **)',
); );
expect(normalizeCodeLocInfo(caughtErrors[0].ownerStack)).toBe( expect(normalizeCodeLocInfo(caughtErrors[0].ownerStack)).toBe(
__DEV__ && gate(flags => flags.enableOwnerStacks) __DEV__ ? '\n in Bar (at **)' + '\n in Foo (at **)' : null,
? '\n in Bar (at **)' + '\n in Foo (at **)'
: null,
); );
}); });
}); });

View File

@ -269,9 +269,7 @@ if (!__EXPERIMENTAL__) {
: '\n in div (at **)' + '\n in div (at **)', : '\n in div (at **)' + '\n in div (at **)',
); );
expect(normalizeCodeLocInfo(caughtErrors[0].ownerStack)).toBe( expect(normalizeCodeLocInfo(caughtErrors[0].ownerStack)).toBe(
__DEV__ && gate(flags => flags.enableOwnerStacks) __DEV__ ? '\n in Bar (at **)' + '\n in Foo (at **)' : null,
? '\n in Bar (at **)' + '\n in Foo (at **)'
: null,
); );
}); });
}); });

View File

@ -875,10 +875,7 @@ describe('ReactFabric', () => {
}); });
assertConsoleErrorDev([ assertConsoleErrorDev([
'Text strings must be rendered within a <Text> component.\n' + 'Text strings must be rendered within a <Text> component.\n' +
' in RCTScrollView (at **)' + ' in RCTScrollView (at **)',
(gate(flags => !flags.enableOwnerStacks)
? '\n in RCTText (at **)'
: ''),
]); ]);
}); });

View File

@ -7,8 +7,6 @@
import isArray from 'shared/isArray'; import isArray from 'shared/isArray';
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import {runWithFiberInDEV} from 'react-reconciler/src/ReactCurrentFiber'; import {runWithFiberInDEV} from 'react-reconciler/src/ReactCurrentFiber';
let hasError = false; let hasError = false;
@ -99,7 +97,7 @@ export function executeDispatchesInOrder(event) {
// Listeners and Instances are two parallel arrays that are always in sync. // Listeners and Instances are two parallel arrays that are always in sync.
const listener = dispatchListeners[i]; const listener = dispatchListeners[i];
const instance = dispatchInstances[i]; const instance = dispatchInstances[i];
if (__DEV__ && enableOwnerStacks && instance !== null) { if (__DEV__ && instance !== null) {
runWithFiberInDEV(instance, executeDispatch, event, listener, instance); runWithFiberInDEV(instance, executeDispatch, event, listener, instance);
} else { } else {
executeDispatch(event, listener, instance); executeDispatch(event, listener, instance);
@ -108,7 +106,7 @@ export function executeDispatchesInOrder(event) {
} else if (dispatchListeners) { } else if (dispatchListeners) {
const listener = dispatchListeners; const listener = dispatchListeners;
const instance = dispatchInstances; const instance = dispatchInstances;
if (__DEV__ && enableOwnerStacks && instance !== null) { if (__DEV__ && instance !== null) {
runWithFiberInDEV(instance, executeDispatch, event, listener, instance); runWithFiberInDEV(instance, executeDispatch, event, listener, instance);
} else { } else {
executeDispatch(event, listener, instance); executeDispatch(event, listener, instance);

View File

@ -47,7 +47,6 @@ import isArray from 'shared/isArray';
import { import {
enableAsyncIterableChildren, enableAsyncIterableChildren,
disableLegacyMode, disableLegacyMode,
enableOwnerStacks,
} from 'shared/ReactFeatureFlags'; } from 'shared/ReactFeatureFlags';
import { import {
@ -488,9 +487,7 @@ function createChildReconciler(
if (__DEV__) { if (__DEV__) {
// We treat the parent as the owner for stack purposes. // We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber; created._debugOwner = returnFiber;
if (enableOwnerStacks) { created._debugTask = returnFiber._debugTask;
created._debugTask = returnFiber._debugTask;
}
created._debugInfo = currentDebugInfo; created._debugInfo = currentDebugInfo;
} }
return created; return created;
@ -609,9 +606,7 @@ function createChildReconciler(
if (__DEV__) { if (__DEV__) {
// We treat the parent as the owner for stack purposes. // We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber; created._debugOwner = returnFiber;
if (enableOwnerStacks) { created._debugTask = returnFiber._debugTask;
created._debugTask = returnFiber._debugTask;
}
created._debugInfo = currentDebugInfo; created._debugInfo = currentDebugInfo;
} }
return created; return created;
@ -649,9 +644,7 @@ function createChildReconciler(
if (__DEV__) { if (__DEV__) {
// We treat the parent as the owner for stack purposes. // We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber; created._debugOwner = returnFiber;
if (enableOwnerStacks) { created._debugTask = returnFiber._debugTask;
created._debugTask = returnFiber._debugTask;
}
created._debugInfo = currentDebugInfo; created._debugInfo = currentDebugInfo;
} }
return created; return created;
@ -718,9 +711,7 @@ function createChildReconciler(
if (__DEV__) { if (__DEV__) {
// We treat the parent as the owner for stack purposes. // We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber; created._debugOwner = returnFiber;
if (enableOwnerStacks) { created._debugTask = returnFiber._debugTask;
created._debugTask = returnFiber._debugTask;
}
const prevDebugInfo = pushDebugInfo(newChild._debugInfo); const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
created._debugInfo = currentDebugInfo; created._debugInfo = currentDebugInfo;
currentDebugInfo = prevDebugInfo; currentDebugInfo = prevDebugInfo;
@ -1605,9 +1596,7 @@ function createChildReconciler(
if (__DEV__) { if (__DEV__) {
// We treat the parent as the owner for stack purposes. // We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber; created._debugOwner = returnFiber;
if (enableOwnerStacks) { created._debugTask = returnFiber._debugTask;
created._debugTask = returnFiber._debugTask;
}
created._debugInfo = currentDebugInfo; created._debugInfo = currentDebugInfo;
} }
return created; return created;
@ -1685,9 +1674,7 @@ function createChildReconciler(
if (__DEV__) { if (__DEV__) {
// We treat the parent as the owner for stack purposes. // We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber; created._debugOwner = returnFiber;
if (enableOwnerStacks) { created._debugTask = returnFiber._debugTask;
created._debugTask = returnFiber._debugTask;
}
created._debugInfo = currentDebugInfo; created._debugInfo = currentDebugInfo;
} }
validateFragmentProps(element, created, returnFiber); validateFragmentProps(element, created, returnFiber);
@ -1980,16 +1967,12 @@ function createChildReconciler(
// thing when it's thrown from the same async component but not if you await // thing when it's thrown from the same async component but not if you await
// a promise started from a different component/task. // a promise started from a different component/task.
throwFiber._debugOwner = returnFiber._debugOwner; throwFiber._debugOwner = returnFiber._debugOwner;
if (enableOwnerStacks) { throwFiber._debugTask = returnFiber._debugTask;
throwFiber._debugTask = returnFiber._debugTask;
}
if (debugInfo != null) { if (debugInfo != null) {
for (let i = debugInfo.length - 1; i >= 0; i--) { for (let i = debugInfo.length - 1; i >= 0; i--) {
if (typeof debugInfo[i].stack === 'string') { if (typeof debugInfo[i].stack === 'string') {
throwFiber._debugOwner = (debugInfo[i]: any); throwFiber._debugOwner = (debugInfo[i]: any);
if (enableOwnerStacks) { throwFiber._debugTask = debugInfo[i].debugTask;
throwFiber._debugTask = debugInfo[i].debugTask;
}
break; break;
} }
} }

View File

@ -10,12 +10,8 @@
import type {Fiber} from './ReactInternalTypes'; import type {Fiber} from './ReactInternalTypes';
import ReactSharedInternals from 'shared/ReactSharedInternals'; import ReactSharedInternals from 'shared/ReactSharedInternals';
import { import {getOwnerStackByFiberInDev} from './ReactFiberComponentStack';
getStackByFiberInDevAndProd,
getOwnerStackByFiberInDev,
} from './ReactFiberComponentStack';
import {getComponentNameFromOwner} from 'react-reconciler/src/getComponentNameFromFiber'; import {getComponentNameFromOwner} from 'react-reconciler/src/getComponentNameFromFiber';
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
export let current: Fiber | null = null; export let current: Fiber | null = null;
export let isRendering: boolean = false; export let isRendering: boolean = false;
@ -42,10 +38,7 @@ function getCurrentFiberStackInDev(): string {
// and it is guaranteed to be the work-in-progress version. // and it is guaranteed to be the work-in-progress version.
// TODO: The above comment is not actually true. We might be // TODO: The above comment is not actually true. We might be
// in a commit phase or preemptive set state callback. // in a commit phase or preemptive set state callback.
if (enableOwnerStacks) { return getOwnerStackByFiberInDev(current);
return getOwnerStackByFiberInDev(current);
}
return getStackByFiberInDevAndProd(current);
} }
return ''; return '';
} }
@ -63,12 +56,10 @@ export function runWithFiberInDEV<A0, A1, A2, A3, A4, T>(
const previousFiber = current; const previousFiber = current;
setCurrentFiber(fiber); setCurrentFiber(fiber);
try { try {
if (enableOwnerStacks) { if (fiber !== null && fiber._debugTask) {
if (fiber !== null && fiber._debugTask) { return fiber._debugTask.run(
return fiber._debugTask.run( callback.bind(null, arg0, arg1, arg2, arg3, arg4),
callback.bind(null, arg0, arg1, arg2, arg3, arg4), );
);
}
} }
return callback(arg0, arg1, arg2, arg3, arg4); return callback(arg0, arg1, arg2, arg3, arg4);
} finally { } finally {

View File

@ -40,7 +40,6 @@ import {
enableRenderableContext, enableRenderableContext,
disableLegacyMode, disableLegacyMode,
enableObjectFiber, enableObjectFiber,
enableOwnerStacks,
enableViewTransition, enableViewTransition,
} from 'shared/ReactFeatureFlags'; } from 'shared/ReactFeatureFlags';
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags'; import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
@ -202,10 +201,8 @@ function FiberNode(
// This isn't directly used but is handy for debugging internals: // This isn't directly used but is handy for debugging internals:
this._debugInfo = null; this._debugInfo = null;
this._debugOwner = null; this._debugOwner = null;
if (enableOwnerStacks) { this._debugStack = null;
this._debugStack = null; this._debugTask = null;
this._debugTask = null;
}
this._debugNeedsRemount = false; this._debugNeedsRemount = false;
this._debugHookTypes = null; this._debugHookTypes = null;
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') { if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
@ -293,10 +290,8 @@ function createFiberImplObject(
// This isn't directly used but is handy for debugging internals: // This isn't directly used but is handy for debugging internals:
fiber._debugInfo = null; fiber._debugInfo = null;
fiber._debugOwner = null; fiber._debugOwner = null;
if (enableOwnerStacks) { fiber._debugStack = null;
fiber._debugStack = null; fiber._debugTask = null;
fiber._debugTask = null;
}
fiber._debugNeedsRemount = false; fiber._debugNeedsRemount = false;
fiber._debugHookTypes = null; fiber._debugHookTypes = null;
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') { if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
@ -352,10 +347,8 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
// DEV-only fields // DEV-only fields
workInProgress._debugOwner = current._debugOwner; workInProgress._debugOwner = current._debugOwner;
if (enableOwnerStacks) { workInProgress._debugStack = current._debugStack;
workInProgress._debugStack = current._debugStack; workInProgress._debugTask = current._debugTask;
workInProgress._debugTask = current._debugTask;
}
workInProgress._debugHookTypes = current._debugHookTypes; workInProgress._debugHookTypes = current._debugHookTypes;
} }
@ -766,10 +759,8 @@ export function createFiberFromElement(
); );
if (__DEV__) { if (__DEV__) {
fiber._debugOwner = element._owner; fiber._debugOwner = element._owner;
if (enableOwnerStacks) { fiber._debugStack = element._debugStack;
fiber._debugStack = element._debugStack; fiber._debugTask = element._debugTask;
fiber._debugTask = element._debugTask;
}
} }
return fiber; return fiber;
} }

View File

@ -114,7 +114,6 @@ import {
enableRenderableContext, enableRenderableContext,
disableLegacyMode, disableLegacyMode,
disableDefaultPropsExceptForClasses, disableDefaultPropsExceptForClasses,
enableOwnerStacks,
enableHydrationLaneScheduling, enableHydrationLaneScheduling,
enableViewTransition, enableViewTransition,
} from 'shared/ReactFeatureFlags'; } from 'shared/ReactFeatureFlags';
@ -3782,10 +3781,8 @@ function beginWork(
workInProgress.mode, workInProgress.mode,
workInProgress.lanes, workInProgress.lanes,
); );
if (enableOwnerStacks) { copiedFiber._debugStack = workInProgress._debugStack;
copiedFiber._debugStack = workInProgress._debugStack; copiedFiber._debugTask = workInProgress._debugTask;
copiedFiber._debugTask = workInProgress._debugTask;
}
return remountFiber(current, workInProgress, copiedFiber); return remountFiber(current, workInProgress, copiedFiber);
} }
} }

View File

@ -7,10 +7,7 @@
* @flow * @flow
*/ */
import { import {enableViewTransition} from 'shared/ReactFeatureFlags';
enableOwnerStacks,
enableViewTransition,
} from 'shared/ReactFeatureFlags';
import type {Fiber} from './ReactInternalTypes'; import type {Fiber} from './ReactInternalTypes';
import type {ReactComponentInfo} from 'shared/ReactTypes'; import type {ReactComponentInfo} from 'shared/ReactTypes';
@ -101,7 +98,7 @@ function describeFunctionComponentFrameWithoutLineNumber(fn: Function): string {
} }
export function getOwnerStackByFiberInDev(workInProgress: Fiber): string { export function getOwnerStackByFiberInDev(workInProgress: Fiber): string {
if (!enableOwnerStacks || !__DEV__) { if (!__DEV__) {
return ''; return '';
} }
try { try {

View File

@ -18,8 +18,6 @@ import reportGlobalError from 'shared/reportGlobalError';
import ReactSharedInternals from 'shared/ReactSharedInternals'; import ReactSharedInternals from 'shared/ReactSharedInternals';
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import {bindToConsole} from './ReactFiberConfig'; import {bindToConsole} from './ReactFiberConfig';
// Side-channel since I'm not sure we want to make this part of the public API // Side-channel since I'm not sure we want to make this part of the public API
@ -46,18 +44,6 @@ export function defaultOnUncaughtError(
'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Consider adding an error boundary to your tree to customize error handling behavior.\n' +
'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.'; 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.';
const prevGetCurrentStack = ReactSharedInternals.getCurrentStack;
if (!enableOwnerStacks) {
// The current Fiber is disconnected at this point which means that console printing
// cannot add a component stack since it terminates at the deletion node. This is not
// a problem for owner stacks which are not disconnected but for the parent component
// stacks we need to use the snapshot we've previously extracted.
const componentStack =
errorInfo.componentStack != null ? errorInfo.componentStack : '';
ReactSharedInternals.getCurrentStack = function () {
return componentStack;
};
}
try { try {
console.warn( console.warn(
'%s\n\n%s\n', '%s\n\n%s\n',
@ -66,9 +52,7 @@ export function defaultOnUncaughtError(
// We let our console.error wrapper add the component stack to the end. // We let our console.error wrapper add the component stack to the end.
); );
} finally { } finally {
if (!enableOwnerStacks) { // ignore
ReactSharedInternals.getCurrentStack = prevGetCurrentStack;
}
} }
} }
} }
@ -97,18 +81,6 @@ export function defaultOnCaughtError(
errorBoundaryName || 'Anonymous' errorBoundaryName || 'Anonymous'
}.`; }.`;
const prevGetCurrentStack = ReactSharedInternals.getCurrentStack;
if (!enableOwnerStacks) {
// The current Fiber is disconnected at this point which means that console printing
// cannot add a component stack since it terminates at the deletion node. This is not
// a problem for owner stacks which are not disconnected but for the parent component
// stacks we need to use the snapshot we've previously extracted.
const componentStack =
errorInfo.componentStack != null ? errorInfo.componentStack : '';
ReactSharedInternals.getCurrentStack = function () {
return componentStack;
};
}
try { try {
if ( if (
typeof error === 'object' && typeof error === 'object' &&
@ -138,9 +110,7 @@ export function defaultOnCaughtError(
); );
} }
} finally { } finally {
if (!enableOwnerStacks) { // ignore
ReactSharedInternals.getCurrentStack = prevGetCurrentStack;
}
} }
} else { } else {
// In production, we print the error directly. // In production, we print the error directly.

View File

@ -6,7 +6,6 @@ describe('ErrorBoundaryReconciliation', () => {
let ReactTestRenderer; let ReactTestRenderer;
let span; let span;
let act; let act;
let assertConsoleErrorDev;
beforeEach(() => { beforeEach(() => {
jest.resetModules(); jest.resetModules();
@ -14,8 +13,6 @@ describe('ErrorBoundaryReconciliation', () => {
ReactTestRenderer = require('react-test-renderer'); ReactTestRenderer = require('react-test-renderer');
React = require('react'); React = require('react');
act = require('internal-test-utils').act; act = require('internal-test-utils').act;
assertConsoleErrorDev =
require('internal-test-utils').assertConsoleErrorDev;
DidCatchErrorBoundary = class extends React.Component { DidCatchErrorBoundary = class extends React.Component {
state = {error: null}; state = {error: null};
componentDidCatch(error) { componentDidCatch(error) {
@ -68,9 +65,6 @@ describe('ErrorBoundaryReconciliation', () => {
</ErrorBoundary>, </ErrorBoundary>,
); );
}); });
if (gate(flags => !flags.enableOwnerStacks)) {
assertConsoleErrorDev(['invalid', 'invalid']);
}
const Fallback = fallbackTagName; const Fallback = fallbackTagName;
expect(renderer).toMatchRenderedOutput(<Fallback prop="ErrorBoundary" />); expect(renderer).toMatchRenderedOutput(<Fallback prop="ErrorBoundary" />);

View File

@ -168,9 +168,7 @@ describe('ReactFragment', () => {
'Foo', 'Foo',
'CatchingBoundary', 'CatchingBoundary',
]), ]),
gate(flags => flags.enableOwnerStacks) && __DEV__ __DEV__ ? componentStack(['Bar', 'Foo']) : null,
? componentStack(['Bar', 'Foo'])
: null,
]); ]);
}); });
}); });

View File

@ -744,19 +744,12 @@ describe('ReactFragment', () => {
ReactNoop.render(<Foo condition={false} />); ReactNoop.render(<Foo condition={false} />);
await waitForAll([]); await waitForAll([]);
assertConsoleErrorDev([ assertConsoleErrorDev([
gate('enableOwnerStacks') 'Each child in a list should have a unique "key" prop.\n' +
? 'Each child in a list should have a unique "key" prop.\n' + '\n' +
'\n' + 'Check the render method of `div`. ' +
'Check the render method of `div`. ' + 'It was passed a child from Foo. ' +
'It was passed a child from Foo. ' + 'See https://react.dev/link/warning-keys for more information.\n' +
'See https://react.dev/link/warning-keys for more information.\n' + ' in Foo (at **)',
' in Foo (at **)'
: 'Each child in a list should have a unique "key" prop.\n' +
'\n' +
'Check the render method of `Foo`. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Stateful (at **)\n' +
' in Foo (at **)',
]); ]);
expect(ops).toEqual([]); expect(ops).toEqual([]);

View File

@ -1236,24 +1236,20 @@ describe('ReactHooks', () => {
'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
'In function components, you can read it directly in the function body, ' + 'In function components, you can read it directly in the function body, ' +
'but not inside Hooks like useReducer() or useMemo().\n' + 'but not inside Hooks like useReducer() or useMemo().\n' +
' in App (at **)' + ' in App (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Boundary (at **)'),
'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' + 'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
'You can only call Hooks at the top level of your React function. ' + 'You can only call Hooks at the top level of your React function. ' +
'For more information, see https://react.dev/link/rules-of-hooks\n' + 'For more information, see https://react.dev/link/rules-of-hooks\n' +
' in App (at **)' + ' in App (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Boundary (at **)'),
'Context can only be read while React is rendering. ' + 'Context can only be read while React is rendering. ' +
'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
'In function components, you can read it directly in the function body, ' + 'In function components, you can read it directly in the function body, ' +
'but not inside Hooks like useReducer() or useMemo().\n' + 'but not inside Hooks like useReducer() or useMemo().\n' +
' in App (at **)' + ' in App (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Boundary (at **)'),
'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' + 'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
'You can only call Hooks at the top level of your React function. ' + 'You can only call Hooks at the top level of your React function. ' +
'For more information, see https://react.dev/link/rules-of-hooks\n' + 'For more information, see https://react.dev/link/rules-of-hooks\n' +
' in App (at **)' + ' in App (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Boundary (at **)'),
]); ]);
function Valid() { function Valid() {
@ -1293,24 +1289,20 @@ describe('ReactHooks', () => {
'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
'In function components, you can read it directly in the function body, ' + 'In function components, you can read it directly in the function body, ' +
'but not inside Hooks like useReducer() or useMemo().\n' + 'but not inside Hooks like useReducer() or useMemo().\n' +
' in App (at **)' + ' in App (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Boundary (at **)'),
'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' + 'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
'You can only call Hooks at the top level of your React function. ' + 'You can only call Hooks at the top level of your React function. ' +
'For more information, see https://react.dev/link/rules-of-hooks\n' + 'For more information, see https://react.dev/link/rules-of-hooks\n' +
' in App (at **)' + ' in App (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Boundary (at **)'),
'Context can only be read while React is rendering. ' + 'Context can only be read while React is rendering. ' +
'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
'In function components, you can read it directly in the function body, ' + 'In function components, you can read it directly in the function body, ' +
'but not inside Hooks like useReducer() or useMemo().\n' + 'but not inside Hooks like useReducer() or useMemo().\n' +
' in App (at **)' + ' in App (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Boundary (at **)'),
'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' + 'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
'You can only call Hooks at the top level of your React function. ' + 'You can only call Hooks at the top level of your React function. ' +
'For more information, see https://react.dev/link/rules-of-hooks\n' + 'For more information, see https://react.dev/link/rules-of-hooks\n' +
' in App (at **)' + ' in App (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Boundary (at **)'),
]); ]);
}); });

View File

@ -1803,14 +1803,10 @@ describe('ReactIncremental', () => {
' in Intl (at **)', ' in Intl (at **)',
'ShowLocale uses the legacy contextTypes API which will soon be removed. ' + 'ShowLocale uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in ShowLocale (at **)' + ' in ShowLocale (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Intl (at **)'),
'ShowBoth uses the legacy contextTypes API which will be removed soon. ' + 'ShowBoth uses the legacy contextTypes API which will be removed soon. ' +
'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
' in ShowBoth (at **)' + ' in ShowBoth (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in div (at **)' + '\n in Intl (at **)'),
]); ]);
ReactNoop.render( ReactNoop.render(
@ -1865,16 +1861,10 @@ describe('ReactIncremental', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'Router uses the legacy childContextTypes API which will soon be removed. ' + 'Router uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
' in Router (at **)' + ' in Router (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Intl (at **)'),
'ShowRoute uses the legacy contextTypes API which will soon be removed. ' + 'ShowRoute uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ' in Indirection (at **)',
? ' in Indirection (at **)'
: ' in ShowRoute (at **)\n' +
' in Indirection (at **)\n' +
' in Router (at **)\n' +
' in Intl (at **)'),
]); ]);
}); });
@ -1972,8 +1962,7 @@ describe('ReactIncremental', () => {
' in Intl (at **)', ' in Intl (at **)',
'ShowLocale uses the legacy contextTypes API which will soon be removed. ' + 'ShowLocale uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in ShowLocale (at **)' + ' in ShowLocale (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Intl (at **)'),
]); ]);
await waitForAll([ await waitForAll([
@ -2068,22 +2057,10 @@ describe('ReactIncremental', () => {
' in Intl (at **)', ' in Intl (at **)',
'ShowLocaleClass uses the legacy contextTypes API which will soon be removed. ' + 'ShowLocaleClass uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in ShowLocaleClass (at **)' + ' in ShowLocaleClass (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in Stateful (at **)' +
'\n in IndirectionClass (at **)' +
'\n in IndirectionFn (at **)' +
' in Intl (at **)'),
'ShowLocaleFn uses the legacy contextTypes API which will be removed soon. ' + 'ShowLocaleFn uses the legacy contextTypes API which will be removed soon. ' +
'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
' in ShowLocaleFn (at **)' + ' in ShowLocaleFn (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in Stateful (at **)' +
'\n in IndirectionClass (at **)' +
'\n in IndirectionFn (at **)' +
' in Intl (at **)'),
]); ]);
statefulInst.setState({x: 1}); statefulInst.setState({x: 1});
@ -2174,26 +2151,14 @@ describe('ReactIncremental', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'Intl uses the legacy childContextTypes API which will soon be removed. ' + 'Intl uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in Intl (at **)\n') +
' in Stateful (at **)', ' in Stateful (at **)',
'ShowLocaleClass uses the legacy contextTypes API which will soon be removed. ' + 'ShowLocaleClass uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in ShowLocaleClass (at **)' + ' in ShowLocaleClass (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in IndirectionClass (at **)' +
'\n in IndirectionFn (at **)' +
'\n in Intl (at **)' +
'\n in Stateful (at **)'),
'ShowLocaleFn uses the legacy contextTypes API which will be removed soon. ' + 'ShowLocaleFn uses the legacy contextTypes API which will be removed soon. ' +
'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
' in ShowLocaleFn (at **)' + ' in ShowLocaleFn (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in IndirectionClass (at **)' +
'\n in IndirectionFn (at **)' +
'\n in Intl (at **)' +
'\n in Stateful (at **)'),
]); ]);
statefulInst.setState({locale: 'gr'}); statefulInst.setState({locale: 'gr'});
@ -2255,7 +2220,6 @@ describe('ReactIncremental', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'Child uses the legacy childContextTypes API which will soon be removed. ' + 'Child uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in Child (at **)\n') +
' in Middle (at **)\n' + ' in Middle (at **)\n' +
' in Root (at **)', ' in Root (at **)',
]); ]);
@ -2309,7 +2273,6 @@ describe('ReactIncremental', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'ContextProvider uses the legacy childContextTypes API which will soon be removed. ' + 'ContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in ContextProvider (at **)\n') +
' in Root (at **)', ' in Root (at **)',
]); ]);
@ -2511,10 +2474,7 @@ describe('ReactIncremental', () => {
' in TopContextProvider (at **)', ' in TopContextProvider (at **)',
'Child uses the legacy contextTypes API which will soon be removed. ' + 'Child uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in Child (at **)' + ' in Child (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in Middle (at **)' + '\n in TopContextProvider (at **)'),
]); ]);
instance.updateCount(); instance.updateCount();
await waitForAll(['count:1']); await waitForAll(['count:1']);
@ -2578,17 +2538,10 @@ describe('ReactIncremental', () => {
' in TopContextProvider (at **)', ' in TopContextProvider (at **)',
'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. ' + 'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
' in MiddleContextProvider (at **)' + ' in MiddleContextProvider (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in TopContextProvider (at **)'),
'Child uses the legacy contextTypes API which will soon be removed. ' + 'Child uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in Child (at **)' + ' in Child (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in MiddleContextProvider (at **)' +
'\n in TopContextProvider (at **)'),
]); ]);
instance.updateCount(); instance.updateCount();
await waitForAll(['count:1']); await waitForAll(['count:1']);
@ -2661,19 +2614,10 @@ describe('ReactIncremental', () => {
' in TopContextProvider (at **)', ' in TopContextProvider (at **)',
'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. ' + 'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
' in MiddleContextProvider (at **)' + ' in MiddleContextProvider (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in MiddleScu (at **)' +
'\n in TopContextProvider (at **)'),
'Child uses the legacy contextTypes API which will soon be removed. ' + 'Child uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in Child (at **)' + ' in Child (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in MiddleContextProvider (at **)' +
'\n in MiddleScu (at **)' +
'\n in TopContextProvider (at **)'),
]); ]);
instance.updateCount(); instance.updateCount();
await waitForAll([]); await waitForAll([]);
@ -2756,19 +2700,10 @@ describe('ReactIncremental', () => {
' in TopContextProvider (at **)', ' in TopContextProvider (at **)',
'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. ' + 'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
' in MiddleContextProvider (at **)' + ' in MiddleContextProvider (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in MiddleScu (at **)' +
'\n in TopContextProvider (at **)'),
'Child uses the legacy contextTypes API which will soon be removed. ' + 'Child uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in Child (at **)' + ' in Child (at **)',
(gate('enableOwnerStacks')
? ''
: '\n in MiddleContextProvider (at **)' +
'\n in MiddleScu (at **)' +
'\n in TopContextProvider (at **)'),
]); ]);
topInstance.updateCount(); topInstance.updateCount();
await waitForAll([]); await waitForAll([]);

View File

@ -1222,8 +1222,7 @@ describe('ReactIncrementalErrorHandling', () => {
' in Provider (at **)', ' in Provider (at **)',
'Connector uses the legacy contextTypes API which will be removed soon. ' + 'Connector uses the legacy contextTypes API which will be removed soon. ' +
'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
' in Connector (at **)' + ' in Connector (at **)',
(gate('enableOwnerStacks') ? '' : '\n in Provider (at **)'),
]); ]);
// If the context stack does not unwind, span will get 'abcde' // If the context stack does not unwind, span will get 'abcde'
@ -1254,23 +1253,6 @@ describe('ReactIncrementalErrorHandling', () => {
</ErrorBoundary>, </ErrorBoundary>,
); );
await waitForAll([]); await waitForAll([]);
if (gate(flags => !flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined. ' +
"You likely forgot to export your component from the file it's defined in, " +
'or you might have mixed up default and named imports.\n' +
' in BrokenRender (at **)\n' +
' in ErrorBoundary (at **)',
// React retries once on error
'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined. ' +
"You likely forgot to export your component from the file it's defined in, " +
'or you might have mixed up default and named imports.\n' +
' in BrokenRender (at **)\n' +
' in ErrorBoundary (at **)',
]);
}
expect(ReactNoop).toMatchRenderedOutput( expect(ReactNoop).toMatchRenderedOutput(
<span <span
@ -1319,23 +1301,7 @@ describe('ReactIncrementalErrorHandling', () => {
</ErrorBoundary>, </ErrorBoundary>,
); );
await waitForAll([]); await waitForAll([]);
if (gate(flags => !flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined. ' +
"You likely forgot to export your component from the file it's defined in, " +
'or you might have mixed up default and named imports.\n' +
' in BrokenRender (at **)\n' +
' in ErrorBoundary (at **)',
// React retries once on error
'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined. ' +
"You likely forgot to export your component from the file it's defined in, " +
'or you might have mixed up default and named imports.\n' +
' in BrokenRender (at **)\n' +
' in ErrorBoundary (at **)',
]);
}
expect(ReactNoop).toMatchRenderedOutput( expect(ReactNoop).toMatchRenderedOutput(
<span <span
prop={ prop={
@ -1354,17 +1320,6 @@ describe('ReactIncrementalErrorHandling', () => {
it('recovers from uncaught reconciler errors', async () => { it('recovers from uncaught reconciler errors', async () => {
const InvalidType = undefined; const InvalidType = undefined;
ReactNoop.render(<InvalidType />); ReactNoop.render(<InvalidType />);
if (gate(flags => !flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined. ' +
"You likely forgot to export your component from the file it's defined in, " +
'or you might have mixed up default and named imports.',
],
{withoutStack: true},
);
}
await waitForThrow( await waitForThrow(
'Element type is invalid: expected a string (for built-in components) or ' + 'Element type is invalid: expected a string (for built-in components) or ' +

View File

@ -94,11 +94,7 @@ describe('ReactIncrementalErrorLogging', () => {
// The component stack is not added without the polyfill/devtools. // The component stack is not added without the polyfill/devtools.
// expect.stringMatching( // expect.stringMatching(
// new RegExp( // new RegExp(
// gate(flags => flags.enableOwnerStacks) // '\\s+(in|at) ErrorThrowingComponent'
// ? '\\s+(in|at) ErrorThrowingComponent'
// : '\\s+(in|at) ErrorThrowingComponent (.*)\n' +
// '\\s+(in|at) span(.*)\n' +
// '\\s+(in|at) div(.*)',
// ), // ),
// ), // ),
); );
@ -143,11 +139,7 @@ describe('ReactIncrementalErrorLogging', () => {
// The component stack is not added without the polyfill/devtools. // The component stack is not added without the polyfill/devtools.
// expect.stringMatching( // expect.stringMatching(
// new RegExp( // new RegExp(
// gate(flags => flags.enableOwnerStacks) // '\\s+(in|at) ErrorThrowingComponent'
// ? '\\s+(in|at) ErrorThrowingComponent'
// : '\\s+(in|at) ErrorThrowingComponent (.*)\n' +
// '\\s+(in|at) span(.*)\n' +
// '\\s+(in|at) div(.*)',
// ), // ),
// ), // ),
); );
@ -204,12 +196,7 @@ describe('ReactIncrementalErrorLogging', () => {
// The component stack is not added without the polyfill/devtools. // The component stack is not added without the polyfill/devtools.
// expect.stringMatching( // expect.stringMatching(
// new RegExp( // new RegExp(
// gate(flags => flags.enableOwnerStacks) // '\\s+(in|at) ErrorThrowingComponent'
// ? '\\s+(in|at) ErrorThrowingComponent'
// : '\\s+(in|at) ErrorThrowingComponent (.*)\n' +
// '\\s+(in|at) span(.*)\n' +
// '\\s+(in|at) ErrorBoundary(.*)\n' +
// '\\s+(in|at) div(.*)',
// ), // ),
// ), // ),
); );
@ -287,11 +274,7 @@ describe('ReactIncrementalErrorLogging', () => {
), ),
// The component stack is not added without the polyfill/devtools. // The component stack is not added without the polyfill/devtools.
// expect.stringMatching( // expect.stringMatching(
// gate(flag => flag.enableOwnerStacks) // new RegExp('\\s+(in|at) Foo')
// ? new RegExp('\\s+(in|at) Foo')
// : new RegExp(
// '\\s+(in|at) Foo (.*)\n' + '\\s+(in|at) ErrorBoundary(.*)',
// ),
// ), // ),
); );
} else { } else {

View File

@ -240,9 +240,6 @@ describe('ReactLazy', () => {
' }\n\n' + ' }\n\n' +
'Your code should look like: \n ' + 'Your code should look like: \n ' +
"const MyComponent = lazy(() => import('./MyComponent'))\n" + "const MyComponent = lazy(() => import('./MyComponent'))\n" +
(gate('enableOwnerStacks')
? ''
: ' in Lazy (at **)\n' + ' in Suspense (at **)\n') +
' in App (at **)', ' in App (at **)',
'lazy: Expected the result of a dynamic import() call. ' + 'lazy: Expected the result of a dynamic import() call. ' +
'Instead received: function Text(props) {\n' + 'Instead received: function Text(props) {\n' +
@ -251,9 +248,6 @@ describe('ReactLazy', () => {
' }\n\n' + ' }\n\n' +
'Your code should look like: \n ' + 'Your code should look like: \n ' +
"const MyComponent = lazy(() => import('./MyComponent'))\n" + "const MyComponent = lazy(() => import('./MyComponent'))\n" +
(gate('enableOwnerStacks')
? ''
: ' in Lazy (at **)\n' + ' in Suspense (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
expect(root).not.toMatchRenderedOutput('Hi'); expect(root).not.toMatchRenderedOutput('Hi');
@ -749,8 +743,7 @@ describe('ReactLazy', () => {
'T: Support for defaultProps ' + 'T: Support for defaultProps ' +
'will be removed from function components in a future major ' + 'will be removed from function components in a future major ' +
'release. Use JavaScript default parameters instead.\n' + 'release. Use JavaScript default parameters instead.\n' +
' in T (at **)\n' + ' in T (at **)',
' in Suspense (at **)',
]); ]);
expect(root).toMatchRenderedOutput('Hi Bye'); expect(root).toMatchRenderedOutput('Hi Bye');
@ -855,11 +848,15 @@ describe('ReactLazy', () => {
); );
}); });
async function verifyResolvesProps( // @gate !disableDefaultPropsExceptForClasses
Add, it('resolves props for function component with defaultProps', async () => {
shouldWarnAboutFunctionDefaultProps, function Add(props) {
shouldWarnAboutMemoDefaultProps, expect(props.innerWithDefault).toBe(42);
) { return props.inner + props.outer;
}
Add.defaultProps = {
innerWithDefault: 42,
};
const LazyAdd = lazy(() => fakeImport(Add)); const LazyAdd = lazy(() => fakeImport(Add));
const root = ReactTestRenderer.create( const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}> <Suspense fallback={<Text text="Loading..." />}>
@ -876,18 +873,10 @@ describe('ReactLazy', () => {
// Mount // Mount
await act(() => resolveFakeImport(Add)); await act(() => resolveFakeImport(Add));
if (shouldWarnAboutFunctionDefaultProps) { assertConsoleErrorDev([
assertConsoleErrorDev([ 'Add: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.\n' +
'Add: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.\n' + ' in Add (at **)',
' in Add (at **)\n' + ]);
' in Suspense (at **)',
]);
} else if (shouldWarnAboutMemoDefaultProps) {
assertConsoleErrorDev([
'Add: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.\n' +
' in Suspense (at **)',
]);
}
expect(root).toMatchRenderedOutput('22'); expect(root).toMatchRenderedOutput('22');
@ -899,25 +888,38 @@ describe('ReactLazy', () => {
); );
await waitForAll([]); await waitForAll([]);
expect(root).toMatchRenderedOutput('0'); expect(root).toMatchRenderedOutput('0');
}
// @gate !disableDefaultPropsExceptForClasses
it('resolves props for function component with defaultProps', async () => {
function Add(props) {
expect(props.innerWithDefault).toBe(42);
return props.inner + props.outer;
}
Add.defaultProps = {
innerWithDefault: 42,
};
await verifyResolvesProps(Add, true);
}); });
it('resolves props for function component without defaultProps', async () => { it('resolves props for function component without defaultProps', async () => {
function Add(props) { function Add(props) {
return props.inner + props.outer; return props.inner + props.outer;
} }
await verifyResolvesProps(Add); const LazyAdd = lazy(() => fakeImport(Add));
const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner="2" outer="2" />
</Suspense>,
{
unstable_isConcurrent: true,
},
);
await waitForAll(['Loading...']);
expect(root).not.toMatchRenderedOutput('22');
// Mount
await act(() => resolveFakeImport(Add));
expect(root).toMatchRenderedOutput('22');
// Update
root.update(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner={false} outer={false} />
</Suspense>,
);
await waitForAll([]);
expect(root).toMatchRenderedOutput('0');
}); });
it('resolves props for class component with defaultProps', async () => { it('resolves props for class component with defaultProps', async () => {
@ -930,7 +932,32 @@ describe('ReactLazy', () => {
Add.defaultProps = { Add.defaultProps = {
innerWithDefault: 42, innerWithDefault: 42,
}; };
await verifyResolvesProps(Add); const LazyAdd = lazy(() => fakeImport(Add));
const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner="2" outer="2" />
</Suspense>,
{
unstable_isConcurrent: true,
},
);
await waitForAll(['Loading...']);
expect(root).not.toMatchRenderedOutput('22');
// Mount
await act(() => resolveFakeImport(Add));
expect(root).toMatchRenderedOutput('22');
// Update
root.update(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner={false} outer={false} />
</Suspense>,
);
await waitForAll([]);
expect(root).toMatchRenderedOutput('0');
}); });
it('resolves props for class component without defaultProps', async () => { it('resolves props for class component without defaultProps', async () => {
@ -939,7 +966,32 @@ describe('ReactLazy', () => {
return this.props.inner + this.props.outer; return this.props.inner + this.props.outer;
} }
} }
await verifyResolvesProps(Add); const LazyAdd = lazy(() => fakeImport(Add));
const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner="2" outer="2" />
</Suspense>,
{
unstable_isConcurrent: true,
},
);
await waitForAll(['Loading...']);
expect(root).not.toMatchRenderedOutput('22');
// Mount
await act(() => resolveFakeImport(Add));
expect(root).toMatchRenderedOutput('22');
// Update
root.update(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner={false} outer={false} />
</Suspense>,
);
await waitForAll([]);
expect(root).toMatchRenderedOutput('0');
}); });
// @gate !disableDefaultPropsExceptForClasses // @gate !disableDefaultPropsExceptForClasses
@ -952,7 +1004,32 @@ describe('ReactLazy', () => {
Add.defaultProps = { Add.defaultProps = {
innerWithDefault: 42, innerWithDefault: 42,
}; };
await verifyResolvesProps(Add); const LazyAdd = lazy(() => fakeImport(Add));
const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner="2" outer="2" />
</Suspense>,
{
unstable_isConcurrent: true,
},
);
await waitForAll(['Loading...']);
expect(root).not.toMatchRenderedOutput('22');
// Mount
await act(() => resolveFakeImport(Add));
expect(root).toMatchRenderedOutput('22');
// Update
root.update(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner={false} outer={false} />
</Suspense>,
);
await waitForAll([]);
expect(root).toMatchRenderedOutput('0');
}); });
it('resolves props for forwardRef component without defaultProps', async () => { it('resolves props for forwardRef component without defaultProps', async () => {
@ -960,7 +1037,33 @@ describe('ReactLazy', () => {
return props.inner + props.outer; return props.inner + props.outer;
}); });
Add.displayName = 'Add'; Add.displayName = 'Add';
await verifyResolvesProps(Add);
const LazyAdd = lazy(() => fakeImport(Add));
const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner="2" outer="2" />
</Suspense>,
{
unstable_isConcurrent: true,
},
);
await waitForAll(['Loading...']);
expect(root).not.toMatchRenderedOutput('22');
// Mount
await act(() => resolveFakeImport(Add));
expect(root).toMatchRenderedOutput('22');
// Update
root.update(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner={false} outer={false} />
</Suspense>,
);
await waitForAll([]);
expect(root).toMatchRenderedOutput('0');
}); });
// @gate !disableDefaultPropsExceptForClasses // @gate !disableDefaultPropsExceptForClasses
@ -973,7 +1076,39 @@ describe('ReactLazy', () => {
Add.defaultProps = { Add.defaultProps = {
innerWithDefault: 42, innerWithDefault: 42,
}; };
await verifyResolvesProps(Add, false, true); const LazyAdd = lazy(() => fakeImport(Add));
const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner="2" outer="2" />
</Suspense>,
{
unstable_isConcurrent: true,
},
);
await waitForAll(['Loading...']);
expect(root).not.toMatchRenderedOutput('22');
// Mount
await act(() => resolveFakeImport(Add));
assertConsoleErrorDev(
[
'Add: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
],
{withoutStack: true},
);
expect(root).toMatchRenderedOutput('22');
// Update
root.update(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner={false} outer={false} />
</Suspense>,
);
await waitForAll([]);
expect(root).toMatchRenderedOutput('0');
}); });
it('resolves props for outer memo component without defaultProps', async () => { it('resolves props for outer memo component without defaultProps', async () => {
@ -981,7 +1116,32 @@ describe('ReactLazy', () => {
return props.inner + props.outer; return props.inner + props.outer;
}; };
Add = React.memo(Add); Add = React.memo(Add);
await verifyResolvesProps(Add); const LazyAdd = lazy(() => fakeImport(Add));
const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner="2" outer="2" />
</Suspense>,
{
unstable_isConcurrent: true,
},
);
await waitForAll(['Loading...']);
expect(root).not.toMatchRenderedOutput('22');
// Mount
await act(() => resolveFakeImport(Add));
expect(root).toMatchRenderedOutput('22');
// Update
root.update(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner={false} outer={false} />
</Suspense>,
);
await waitForAll([]);
expect(root).toMatchRenderedOutput('0');
}); });
// @gate !disableDefaultPropsExceptForClasses // @gate !disableDefaultPropsExceptForClasses
@ -994,7 +1154,40 @@ describe('ReactLazy', () => {
Add.defaultProps = { Add.defaultProps = {
innerWithDefault: 42, innerWithDefault: 42,
}; };
await verifyResolvesProps(React.memo(Add), true); const MemoAdd = React.memo(Add);
const LazyAdd = lazy(() => fakeImport(MemoAdd));
const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner="2" outer="2" />
</Suspense>,
{
unstable_isConcurrent: true,
},
);
await waitForAll(['Loading...']);
expect(root).not.toMatchRenderedOutput('22');
// Mount
await act(() => resolveFakeImport(MemoAdd));
assertConsoleErrorDev(
[
'Add: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
],
{withoutStack: true},
);
expect(root).toMatchRenderedOutput('22');
// Update
root.update(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner={false} outer={false} />
</Suspense>,
);
await waitForAll([]);
expect(root).toMatchRenderedOutput('0');
}); });
it('resolves props for inner memo component without defaultProps', async () => { it('resolves props for inner memo component without defaultProps', async () => {
@ -1002,7 +1195,32 @@ describe('ReactLazy', () => {
return props.inner + props.outer; return props.inner + props.outer;
}; };
Add.displayName = 'Add'; Add.displayName = 'Add';
await verifyResolvesProps(React.memo(Add)); const LazyAdd = lazy(() => fakeImport(Add));
const root = ReactTestRenderer.create(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner="2" outer="2" />
</Suspense>,
{
unstable_isConcurrent: true,
},
);
await waitForAll(['Loading...']);
expect(root).not.toMatchRenderedOutput('22');
// Mount
await act(() => resolveFakeImport(Add));
expect(root).toMatchRenderedOutput('22');
// Update
root.update(
<Suspense fallback={<Text text="Loading..." />}>
<LazyAdd inner={false} outer={false} />
</Suspense>,
);
await waitForAll([]);
expect(root).toMatchRenderedOutput('0');
}); });
// @gate !disableDefaultPropsExceptForClasses // @gate !disableDefaultPropsExceptForClasses
@ -1030,12 +1248,13 @@ describe('ReactLazy', () => {
// Mount // Mount
await act(() => resolveFakeImport(T)); await act(() => resolveFakeImport(T));
assertLog(['Inner default text']); assertLog(['Inner default text']);
assertConsoleErrorDev([ assertConsoleErrorDev(
'T: Support for defaultProps will be removed from function components in a future major release. ' + [
'Use JavaScript default parameters instead.\n' + 'T: Support for defaultProps will be removed from function components in a future major release. ' +
' in T (at **)\n' + 'Use JavaScript default parameters instead.',
' in Suspense (at **)', ],
]); {withoutStack: true},
);
expect(root).toMatchRenderedOutput('Inner default text'); expect(root).toMatchRenderedOutput('Inner default text');
// Update // Update
@ -1074,11 +1293,7 @@ describe('ReactLazy', () => {
'\n' + '\n' +
'Check the render method of `Foo`. ' + 'Check the render method of `Foo`. ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
(gate(flags => flags.enableOwnerStacks) ' in Foo (at **)',
? ' in Foo (at **)'
: ' in Text (at **)\n' +
' in Foo (at **)\n' +
' in Suspense (at **)'),
]); ]);
expect(root).toMatchRenderedOutput(<div>AB</div>); expect(root).toMatchRenderedOutput(<div>AB</div>);
}); });
@ -1154,11 +1369,13 @@ describe('ReactLazy', () => {
// Mount // Mount
await act(() => resolveFakeImport(Add)); await act(() => resolveFakeImport(Add));
assertConsoleErrorDev([ assertConsoleErrorDev(
'Unknown: Support for defaultProps will be removed from memo components in a future major release. ' + [
'Use JavaScript default parameters instead.\n' + 'Unknown: Support for defaultProps will be removed from memo components in a future major release. ' +
' in Suspense (at **)', 'Use JavaScript default parameters instead.',
]); ],
{withoutStack: true},
);
expect(root).toMatchRenderedOutput('4'); expect(root).toMatchRenderedOutput('4');
// Update (shallowly equal) // Update (shallowly equal)
@ -1243,14 +1460,15 @@ describe('ReactLazy', () => {
// Mount // Mount
await act(() => resolveFakeImport(Add)); await act(() => resolveFakeImport(Add));
assertConsoleErrorDev([ assertConsoleErrorDev(
'Memo: Support for defaultProps will be removed from memo components in a future major release. ' + [
'Use JavaScript default parameters instead.\n' + 'Memo: Support for defaultProps will be removed from memo components in a future major release. ' +
' in Suspense (at **)', 'Use JavaScript default parameters instead.',
'Unknown: Support for defaultProps will be removed from memo components in a future major release. ' + 'Unknown: Support for defaultProps will be removed from memo components in a future major release. ' +
'Use JavaScript default parameters instead.\n' + 'Use JavaScript default parameters instead.',
' in Suspense (at **)', ],
]); {withoutStack: true},
);
expect(root).toMatchRenderedOutput('4'); expect(root).toMatchRenderedOutput('4');
// Update // Update

View File

@ -407,12 +407,22 @@ describe('memo', () => {
); );
}); });
assertLog(['Loading...', 15]); assertLog(['Loading...', 15]);
assertConsoleErrorDev([ if (label === 'lazy') {
'Counter: Support for defaultProps will be removed from memo components in a future major release. ' + assertConsoleErrorDev(
'Use JavaScript default parameters instead.\n' + [
(label === 'lazy' ? '' : ' in Indirection (at **)\n') + 'Counter: Support for defaultProps will be removed from memo components in a future major release. ' +
' in Suspense (at **)', 'Use JavaScript default parameters instead.',
]); ],
{withoutStack: true},
);
} else {
assertConsoleErrorDev([
'Counter: Support for defaultProps will be removed from memo components in a future major release. ' +
'Use JavaScript default parameters instead.\n' +
' in Indirection (at **)',
]);
}
expect(ReactNoop).toMatchRenderedOutput(<span prop={15} />); expect(ReactNoop).toMatchRenderedOutput(<span prop={15} />);
// Should bail out because props have not changed // Should bail out because props have not changed
@ -475,12 +485,14 @@ describe('memo', () => {
</div>, </div>,
); );
}); });
assertConsoleErrorDev([ assertConsoleErrorDev(
'Inner: ' + [
'Support for defaultProps will be removed from memo components in a future major release. ' + 'Inner: ' +
'Use JavaScript default parameters instead.\n' + 'Support for defaultProps will be removed from memo components in a future major release. ' +
' in div (at **)', 'Use JavaScript default parameters instead.',
]); ],
{withoutStack: true},
);
expect(root).toMatchRenderedOutput(<div>111</div>); expect(root).toMatchRenderedOutput(<div>111</div>);
await act(async () => { await act(async () => {
@ -576,9 +588,7 @@ describe('memo', () => {
'Each child in a list should have a unique "key" prop. ' + 'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
(gate('enableOwnerStacks') ' in **/ReactMemo-test.js:**:** (at **)',
? ' in **/ReactMemo-test.js:**:** (at **)'
: ' in p (at **)'),
]); ]);
}); });
@ -597,8 +607,7 @@ describe('memo', () => {
'\n\nCheck the top-level render call using <Inner>. It was passed a child from Inner. ' + '\n\nCheck the top-level render call using <Inner>. It was passed a child from Inner. ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Inner (at **)' + ' in Inner (at **)',
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
]); ]);
}); });
@ -619,8 +628,7 @@ describe('memo', () => {
'\n\nCheck the top-level render call using <Inner>. It was passed a child from Inner. ' + '\n\nCheck the top-level render call using <Inner>. It was passed a child from Inner. ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Inner (at **)' + ' in Inner (at **)',
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
]); ]);
}); });
@ -640,8 +648,7 @@ describe('memo', () => {
'\n\nCheck the top-level render call using <Outer>. It was passed a child from Outer. ' + '\n\nCheck the top-level render call using <Outer>. It was passed a child from Outer. ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Outer (at **)' + ' in Outer (at **)',
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
]); ]);
}); });
@ -663,8 +670,7 @@ describe('memo', () => {
'\n\nCheck the top-level render call using <Inner>. It was passed a child from Inner. ' + '\n\nCheck the top-level render call using <Inner>. It was passed a child from Inner. ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Inner (at **)' + ' in Inner (at **)',
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
]); ]);
}); });
} }

View File

@ -41,7 +41,7 @@ describe('ReactOwnerStacks', () => {
} }
}); });
// @gate __DEV__ && enableOwnerStacks // @gate __DEV__
it('can get the component owner stacks during rendering in dev', async () => { it('can get the component owner stacks during rendering in dev', async () => {
let stack; let stack;
@ -75,7 +75,7 @@ describe('ReactOwnerStacks', () => {
it('returns null outside of render', async () => { it('returns null outside of render', async () => {
// Awkward to gate since some builds will have `captureOwnerStack` return null in prod // Awkward to gate since some builds will have `captureOwnerStack` return null in prod
if (__DEV__ && gate('enableOwnerStacks')) { if (__DEV__) {
expect(React.captureOwnerStack()).toBe(null); expect(React.captureOwnerStack()).toBe(null);
await act(() => { await act(() => {

View File

@ -257,9 +257,6 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. Creating ' + 'A component was suspended by an uncached promise. Creating ' +
'promises inside a Client Component or hook is not yet ' + 'promises inside a Client Component or hook is not yet ' +
'supported, except via a Suspense-compatible library or framework.\n' + 'supported, except via a Suspense-compatible library or framework.\n' +
(gate('enableOwnerStacks')
? ''
: ' in Async (at **)\n' + ' in Suspense (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
assertLog(['ABC']); assertLog(['ABC']);
@ -430,20 +427,10 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. Creating ' + 'A component was suspended by an uncached promise. Creating ' +
'promises inside a Client Component or hook is not yet ' + 'promises inside a Client Component or hook is not yet ' +
'supported, except via a Suspense-compatible library or framework.\n' + 'supported, except via a Suspense-compatible library or framework.\n' +
(gate('enableOwnerStacks')
? ''
: ' in Async (at **)\n' +
' in ErrorBoundary (at **)\n' +
' in Suspense (at **)\n') +
' in App (at **)', ' in App (at **)',
'A component was suspended by an uncached promise. Creating ' + 'A component was suspended by an uncached promise. Creating ' +
'promises inside a Client Component or hook is not yet ' + 'promises inside a Client Component or hook is not yet ' +
'supported, except via a Suspense-compatible library or framework.\n' + 'supported, except via a Suspense-compatible library or framework.\n' +
(gate('enableOwnerStacks')
? ''
: ' in Async (at **)\n' +
' in ErrorBoundary (at **)\n' +
' in Suspense (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
assertLog([ assertLog([
@ -617,8 +604,7 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
' in App (at **)\n' + ' in App (at **)',
' in Suspense (at **)',
]); ]);
expect(root).toMatchRenderedOutput('Async'); expect(root).toMatchRenderedOutput('Async');
}); });
@ -667,8 +653,7 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
' in App (at **)\n' + ' in App (at **)',
' in Suspense (at **)',
]); ]);
expect(root).toMatchRenderedOutput('Async'); expect(root).toMatchRenderedOutput('Async');
}); });
@ -1216,8 +1201,7 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
' in AsyncText (at **)\n' + ' in AsyncText (at **)',
' in Suspense (at **)',
]); ]);
expect(root).toMatchRenderedOutput('A(Loading B...)'); expect(root).toMatchRenderedOutput('A(Loading B...)');
@ -1243,9 +1227,7 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
' in AsyncText (at **)\n' + ' in AsyncText (at **)',
' in Suspense (at **)\n' +
' in Suspense (at **)',
]); ]);
expect(root).toMatchRenderedOutput('AB(Loading C...)'); expect(root).toMatchRenderedOutput('AB(Loading C...)');
@ -1263,10 +1245,7 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
' in AsyncText (at **)\n' + ' in AsyncText (at **)',
' in Suspense (at **)\n' +
' in Suspense (at **)\n' +
' in Suspense (at **)',
]); ]);
expect(root).toMatchRenderedOutput('ABC'); expect(root).toMatchRenderedOutput('ABC');
}); });
@ -1301,16 +1280,10 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
(gate('enableOwnerStacks')
? ''
: ' in Async (at **)\n' + ' in Suspense (at **)\n') +
' in App (at **)', ' in App (at **)',
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
(gate('enableOwnerStacks')
? ''
: ' in Async (at **)\n' + ' in Suspense (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
expect(root).toMatchRenderedOutput('A1'); expect(root).toMatchRenderedOutput('A1');
@ -1685,10 +1658,6 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
(gate('enableOwnerStacks')
? ''
: ' in **/ReactUse-test.js:**:** (at **)\n' +
' in Suspense (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
expect(root).toMatchRenderedOutput('Async'); expect(root).toMatchRenderedOutput('Async');
@ -1723,10 +1692,6 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
(gate('enableOwnerStacks')
? ''
: ' in **/ReactUse-test.js:**:** (at **)\n' +
' in Suspense (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
expect(root).toMatchRenderedOutput('Async'); expect(root).toMatchRenderedOutput('Async');
@ -1752,10 +1717,6 @@ describe('ReactUse', () => {
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
(gate('enableOwnerStacks')
? ''
: ' in **/ReactUse-test.js:**:** (at **)\n' +
' in Suspense (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
expect(root).toMatchRenderedOutput('Async!'); expect(root).toMatchRenderedOutput('Async!');
@ -1810,36 +1771,17 @@ describe('ReactUse', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'ContextProvider uses the legacy childContextTypes API which will soon be removed. ' + 'ContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks') ? '' : ' in ContextProvider (at **)\n') +
' in App (at **)', ' in App (at **)',
'Async uses the legacy contextTypes API which will be removed soon. ' + 'Async uses the legacy contextTypes API which will be removed soon. ' +
'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
(gate('enableOwnerStacks')
? ''
: ' in Async (at **)\n' +
' in div (at **)\n' +
' in Suspense (at **)\n' +
' in ContextProvider (at **)\n') +
' in App (at **)', ' in App (at **)',
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
(gate('enableOwnerStacks')
? ''
: ' in Async (at **)\n' +
' in div (at **)\n' +
' in Suspense (at **)\n' +
' in ContextProvider (at **)\n') +
' in App (at **)', ' in App (at **)',
'A component was suspended by an uncached promise. ' + 'A component was suspended by an uncached promise. ' +
'Creating promises inside a Client Component or hook is not yet supported, ' + 'Creating promises inside a Client Component or hook is not yet supported, ' +
'except via a Suspense-compatible library or framework.\n' + 'except via a Suspense-compatible library or framework.\n' +
(gate('enableOwnerStacks')
? ''
: ' in Async (at **)\n' +
' in div (at **)\n' +
' in Suspense (at **)\n' +
' in ContextProvider (at **)\n') +
' in App (at **)', ' in App (at **)',
]); ]);
expect(root).toMatchRenderedOutput( expect(root).toMatchRenderedOutput(
@ -1921,8 +1863,7 @@ describe('ReactUse', () => {
'Only Server Components can be async at the moment. ' + 'Only Server Components can be async at the moment. ' +
"This error is often caused by accidentally adding `'use client'` " + "This error is often caused by accidentally adding `'use client'` " +
'to a module that was originally written for the server.\n' + 'to a module that was originally written for the server.\n' +
' in AsyncClientComponent (at **)' + ' in AsyncClientComponent (at **)',
(gate('enableOwnerStacks') ? '' : '\n in ErrorBoundary (at **)'),
]); ]);
assertLog([ assertLog([
'An unknown Component is an async Client Component. ' + 'An unknown Component is an async Client Component. ' +
@ -1977,8 +1918,7 @@ describe('ReactUse', () => {
'Only Server Components can be async at the moment. ' + 'Only Server Components can be async at the moment. ' +
"This error is often caused by accidentally adding `'use client'` " + "This error is often caused by accidentally adding `'use client'` " +
'to a module that was originally written for the server.\n' + 'to a module that was originally written for the server.\n' +
' in AsyncClientComponent (at **)' + ' in AsyncClientComponent (at **)',
(gate('enableOwnerStacks') ? '' : '\n in ErrorBoundary (at **)'),
]); ]);
assertLog([ assertLog([
'An unknown Component is an async Client Component. ' + 'An unknown Component is an async Client Component. ' +

View File

@ -1170,25 +1170,15 @@ describe('ReactFlightDOMBrowser', () => {
); );
const result = await ReactServerDOMClient.createFromReadableStream(stream); const result = await ReactServerDOMClient.createFromReadableStream(stream);
if (!gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]);
}
await act(() => { await act(() => {
root.render(result); root.render(result);
}); });
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev([
assertConsoleErrorDev([ 'Each child in a list should have a unique "key" prop.\n\n' +
'Each child in a list should have a unique "key" prop.\n\n' + 'Check the top-level render call using <ParentClient>. ' +
'Check the top-level render call using <ParentClient>. ' + 'See https://react.dev/link/warning-keys for more information.\n' +
'See https://react.dev/link/warning-keys for more information.\n' + ' in div (at **)',
' in div (at **)', ]);
]);
}
}); });
it('basic use(promise)', async () => { it('basic use(promise)', async () => {

View File

@ -1020,7 +1020,7 @@ describe('ReactFlightDOMEdge', () => {
} }
}); });
// @gate __DEV__ && enableOwnerStacks // @gate __DEV__
it('can get the component owner stacks asynchronously', async () => { it('can get the component owner stacks asynchronously', async () => {
let stack; let stack;

View File

@ -26,10 +26,7 @@ import {
REACT_VIEW_TRANSITION_TYPE, REACT_VIEW_TRANSITION_TYPE,
} from 'shared/ReactSymbols'; } from 'shared/ReactSymbols';
import { import {enableViewTransition} from 'shared/ReactFeatureFlags';
enableOwnerStacks,
enableViewTransition,
} from 'shared/ReactFeatureFlags';
import {formatOwnerStack} from 'shared/ReactOwnerStackFrames'; import {formatOwnerStack} from 'shared/ReactOwnerStackFrames';
@ -134,7 +131,7 @@ function describeFunctionComponentFrameWithoutLineNumber(fn: Function): string {
export function getOwnerStackByComponentStackNodeInDev( export function getOwnerStackByComponentStackNodeInDev(
componentStack: ComponentStackNode, componentStack: ComponentStackNode,
): string { ): string {
if (!enableOwnerStacks || !__DEV__) { if (!__DEV__) {
return ''; return '';
} }
try { try {

View File

@ -165,7 +165,6 @@ import {
enableRenderableContext, enableRenderableContext,
disableDefaultPropsExceptForClasses, disableDefaultPropsExceptForClasses,
enableAsyncIterableChildren, enableAsyncIterableChildren,
enableOwnerStacks,
enableViewTransition, enableViewTransition,
} from 'shared/ReactFeatureFlags'; } from 'shared/ReactFeatureFlags';
@ -787,7 +786,7 @@ function createRenderTask(
if (!disableLegacyContext) { if (!disableLegacyContext) {
task.legacyContext = legacyContext; task.legacyContext = legacyContext;
} }
if (__DEV__ && enableOwnerStacks) { if (__DEV__) {
task.debugTask = debugTask; task.debugTask = debugTask;
} }
abortSet.add(task); abortSet.add(task);
@ -840,7 +839,7 @@ function createReplayTask(
if (!disableLegacyContext) { if (!disableLegacyContext) {
task.legacyContext = legacyContext; task.legacyContext = legacyContext;
} }
if (__DEV__ && enableOwnerStacks) { if (__DEV__) {
task.debugTask = debugTask; task.debugTask = debugTask;
} }
abortSet.add(task); abortSet.add(task);
@ -875,12 +874,9 @@ function getCurrentStackInDEV(): string {
if (currentTaskInDEV === null || currentTaskInDEV.componentStack === null) { if (currentTaskInDEV === null || currentTaskInDEV.componentStack === null) {
return ''; return '';
} }
if (enableOwnerStacks) { return getOwnerStackByComponentStackNodeInDev(
return getOwnerStackByComponentStackNodeInDev( currentTaskInDEV.componentStack,
currentTaskInDEV.componentStack, );
);
}
return getStackByComponentStackNode(currentTaskInDEV.componentStack);
} }
return ''; return '';
} }
@ -907,18 +903,16 @@ function pushServerComponentStack(
if (typeof componentInfo.name !== 'string') { if (typeof componentInfo.name !== 'string') {
continue; continue;
} }
if (enableOwnerStacks && componentInfo.debugStack === undefined) { if (componentInfo.debugStack === undefined) {
continue; continue;
} }
task.componentStack = { task.componentStack = {
parent: task.componentStack, parent: task.componentStack,
type: componentInfo, type: componentInfo,
owner: componentInfo.owner, owner: componentInfo.owner,
stack: enableOwnerStacks ? componentInfo.debugStack : null, stack: componentInfo.debugStack,
}; };
if (enableOwnerStacks) { task.debugTask = (componentInfo.debugTask: any);
task.debugTask = (componentInfo.debugTask: any);
}
} }
} }
} }
@ -934,12 +928,10 @@ function pushComponentStack(task: Task): void {
const element: any = node; const element: any = node;
const type = element.type; const type = element.type;
const owner = __DEV__ ? element._owner : null; const owner = __DEV__ ? element._owner : null;
const stack = __DEV__ && enableOwnerStacks ? element._debugStack : null; const stack = __DEV__ ? element._debugStack : null;
if (__DEV__) { if (__DEV__) {
pushServerComponentStack(task, element._debugInfo); pushServerComponentStack(task, element._debugInfo);
if (enableOwnerStacks) { task.debugTask = element._debugTask;
task.debugTask = element._debugTask;
}
} }
task.componentStack = createComponentStackFromType( task.componentStack = createComponentStackFromType(
task.componentStack, task.componentStack,
@ -1056,7 +1048,7 @@ function logPostpone(
// If this callback errors, we intentionally let that error bubble up to become a fatal error // If this callback errors, we intentionally let that error bubble up to become a fatal error
// so that someone fixes the error reporting instead of hiding it. // so that someone fixes the error reporting instead of hiding it.
const onPostpone = request.onPostpone; const onPostpone = request.onPostpone;
if (__DEV__ && enableOwnerStacks && debugTask) { if (__DEV__ && debugTask) {
debugTask.run(onPostpone.bind(null, reason, postponeInfo)); debugTask.run(onPostpone.bind(null, reason, postponeInfo));
} else { } else {
onPostpone(reason, postponeInfo); onPostpone(reason, postponeInfo);
@ -1073,7 +1065,7 @@ function logRecoverableError(
// so that someone fixes the error reporting instead of hiding it. // so that someone fixes the error reporting instead of hiding it.
const onError = request.onError; const onError = request.onError;
const errorDigest = const errorDigest =
__DEV__ && enableOwnerStacks && debugTask __DEV__ && debugTask
? debugTask.run(onError.bind(null, error, errorInfo)) ? debugTask.run(onError.bind(null, error, errorInfo))
: onError(error, errorInfo); : onError(error, errorInfo);
if (errorDigest != null && typeof errorDigest !== 'string') { if (errorDigest != null && typeof errorDigest !== 'string') {
@ -1101,7 +1093,7 @@ function fatalError(
// It's also called if React itself or its host configs errors. // It's also called if React itself or its host configs errors.
const onShellError = request.onShellError; const onShellError = request.onShellError;
const onFatalError = request.onFatalError; const onFatalError = request.onFatalError;
if (__DEV__ && enableOwnerStacks && debugTask) { if (__DEV__ && debugTask) {
debugTask.run(onShellError.bind(null, error)); debugTask.run(onShellError.bind(null, error));
debugTask.run(onFatalError.bind(null, error)); debugTask.run(onFatalError.bind(null, error));
} else { } else {
@ -1261,7 +1253,7 @@ function renderSuspenseBoundary(
task.componentStack, task.componentStack,
task.isFallback, task.isFallback,
!disableLegacyContext ? task.legacyContext : emptyContextObject, !disableLegacyContext ? task.legacyContext : emptyContextObject,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
pushComponentStack(suspendedPrimaryTask); pushComponentStack(suspendedPrimaryTask);
request.pingedTasks.push(suspendedPrimaryTask); request.pingedTasks.push(suspendedPrimaryTask);
@ -1334,7 +1326,7 @@ function renderSuspenseBoundary(
request, request,
postponeInstance.message, postponeInstance.message,
thrownInfo, thrownInfo,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
// TODO: Figure out a better signal than a magic digest value. // TODO: Figure out a better signal than a magic digest value.
errorDigest = 'POSTPONE'; errorDigest = 'POSTPONE';
@ -1343,7 +1335,7 @@ function renderSuspenseBoundary(
request, request,
error, error,
thrownInfo, thrownInfo,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
} }
encodeErrorForBoundary( encodeErrorForBoundary(
@ -1387,7 +1379,7 @@ function renderSuspenseBoundary(
task.componentStack, task.componentStack,
true, true,
!disableLegacyContext ? task.legacyContext : emptyContextObject, !disableLegacyContext ? task.legacyContext : emptyContextObject,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
pushComponentStack(suspendedFallbackTask); pushComponentStack(suspendedFallbackTask);
// TODO: This should be queued at a separate lower priority queue so that we only work // TODO: This should be queued at a separate lower priority queue so that we only work
@ -1485,7 +1477,7 @@ function replaySuspenseBoundary(
request, request,
postponeInstance.message, postponeInstance.message,
thrownInfo, thrownInfo,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
// TODO: Figure out a better signal than a magic digest value. // TODO: Figure out a better signal than a magic digest value.
errorDigest = 'POSTPONE'; errorDigest = 'POSTPONE';
@ -1494,7 +1486,7 @@ function replaySuspenseBoundary(
request, request,
error, error,
thrownInfo, thrownInfo,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
} }
encodeErrorForBoundary( encodeErrorForBoundary(
@ -1545,7 +1537,7 @@ function replaySuspenseBoundary(
task.componentStack, task.componentStack,
true, true,
!disableLegacyContext ? task.legacyContext : emptyContextObject, !disableLegacyContext ? task.legacyContext : emptyContextObject,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
pushComponentStack(suspendedFallbackTask); pushComponentStack(suspendedFallbackTask);
@ -1587,7 +1579,7 @@ function renderPreamble(
task.componentStack, task.componentStack,
task.isFallback, task.isFallback,
!disableLegacyContext ? task.legacyContext : emptyContextObject, !disableLegacyContext ? task.legacyContext : emptyContextObject,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
pushComponentStack(preambleTask); pushComponentStack(preambleTask);
request.pingedTasks.push(preambleTask); request.pingedTasks.push(preambleTask);
@ -2489,7 +2481,7 @@ function replayElement(
thrownInfo, thrownInfo,
childNodes, childNodes,
childSlots, childSlots,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
} }
task.replay = replay; task.replay = replay;
@ -2654,15 +2646,14 @@ function renderNodeDestructive(
task.childIndex = childIndex; task.childIndex = childIndex;
const previousComponentStack = task.componentStack; const previousComponentStack = task.componentStack;
const previousDebugTask = const previousDebugTask = __DEV__ ? task.debugTask : null;
__DEV__ && enableOwnerStacks ? task.debugTask : null;
pushComponentStack(task); pushComponentStack(task);
retryNode(request, task); retryNode(request, task);
task.componentStack = previousComponentStack; task.componentStack = previousComponentStack;
if (__DEV__ && enableOwnerStacks) { if (__DEV__) {
task.debugTask = previousDebugTask; task.debugTask = previousDebugTask;
} }
} }
@ -2689,8 +2680,7 @@ function retryNode(request: Request, task: Task): void {
const refProp = props.ref; const refProp = props.ref;
const ref = refProp !== undefined ? refProp : null; const ref = refProp !== undefined ? refProp : null;
const debugTask: null | ConsoleTask = const debugTask: null | ConsoleTask = __DEV__ ? task.debugTask : null;
__DEV__ && enableOwnerStacks ? task.debugTask : null;
const name = getComponentNameFromType(type); const name = getComponentNameFromType(type);
const keyOrIndex = const keyOrIndex =
@ -3002,7 +2992,7 @@ function replayFragment(
thrownInfo, thrownInfo,
childNodes, childNodes,
childSlots, childSlots,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
} }
task.replay = replay; task.replay = replay;
@ -3094,7 +3084,7 @@ function warnForMissingKey(request: Request, task: Task, child: mixed): void {
task.componentStack, task.componentStack,
(child: any).type, (child: any).type,
(child: any)._owner, (child: any)._owner,
enableOwnerStacks ? (child: any)._debugStack : null, (child: any)._debugStack,
); );
task.componentStack = stackFrame; task.componentStack = stackFrame;
console.error( console.error(
@ -3117,9 +3107,7 @@ function renderChildrenArray(
const previousComponentStack = task.componentStack; const previousComponentStack = task.componentStack;
let previousDebugTask = null; let previousDebugTask = null;
if (__DEV__) { if (__DEV__) {
if (enableOwnerStacks) { previousDebugTask = task.debugTask;
previousDebugTask = task.debugTask;
}
// We read debugInfo from task.node instead of children because it might have been an // We read debugInfo from task.node instead of children because it might have been an
// unwrapped iterable so we read from the original node. // unwrapped iterable so we read from the original node.
pushServerComponentStack(task, (task.node: any)._debugInfo); pushServerComponentStack(task, (task.node: any)._debugInfo);
@ -3137,9 +3125,7 @@ function renderChildrenArray(
task.keyPath = prevKeyPath; task.keyPath = prevKeyPath;
if (__DEV__) { if (__DEV__) {
task.componentStack = previousComponentStack; task.componentStack = previousComponentStack;
if (enableOwnerStacks) { task.debugTask = previousDebugTask;
task.debugTask = previousDebugTask;
}
} }
return; return;
} }
@ -3173,9 +3159,7 @@ function renderChildrenArray(
task.keyPath = prevKeyPath; task.keyPath = prevKeyPath;
if (__DEV__) { if (__DEV__) {
task.componentStack = previousComponentStack; task.componentStack = previousComponentStack;
if (enableOwnerStacks) { task.debugTask = previousDebugTask;
task.debugTask = previousDebugTask;
}
} }
return; return;
} }
@ -3198,9 +3182,7 @@ function renderChildrenArray(
task.keyPath = prevKeyPath; task.keyPath = prevKeyPath;
if (__DEV__) { if (__DEV__) {
task.componentStack = previousComponentStack; task.componentStack = previousComponentStack;
if (enableOwnerStacks) { task.debugTask = previousDebugTask;
task.debugTask = previousDebugTask;
}
} }
} }
@ -3394,12 +3376,7 @@ function injectPostponedHole(
reason: string, reason: string,
thrownInfo: ThrownInfo, thrownInfo: ThrownInfo,
): Segment { ): Segment {
logPostpone( logPostpone(request, reason, thrownInfo, __DEV__ ? task.debugTask : null);
request,
reason,
thrownInfo,
__DEV__ && enableOwnerStacks ? task.debugTask : null,
);
// Something suspended, we'll need to create a new segment and resolve it later. // Something suspended, we'll need to create a new segment and resolve it later.
const segment = task.blockedSegment; const segment = task.blockedSegment;
const insertionIndex = segment.chunks.length; const insertionIndex = segment.chunks.length;
@ -3440,7 +3417,7 @@ function spawnNewSuspendedReplayTask(
task.componentStack, task.componentStack,
task.isFallback, task.isFallback,
!disableLegacyContext ? task.legacyContext : emptyContextObject, !disableLegacyContext ? task.legacyContext : emptyContextObject,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
} }
@ -3482,7 +3459,7 @@ function spawnNewSuspendedRenderTask(
task.componentStack, task.componentStack,
task.isFallback, task.isFallback,
!disableLegacyContext ? task.legacyContext : emptyContextObject, !disableLegacyContext ? task.legacyContext : emptyContextObject,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
} }
@ -3504,8 +3481,7 @@ function renderNode(
const previousKeyPath = task.keyPath; const previousKeyPath = task.keyPath;
const previousTreeContext = task.treeContext; const previousTreeContext = task.treeContext;
const previousComponentStack = task.componentStack; const previousComponentStack = task.componentStack;
const previousDebugTask = const previousDebugTask = __DEV__ ? task.debugTask : null;
__DEV__ && enableOwnerStacks ? task.debugTask : null;
let x; let x;
// Store how much we've pushed at this point so we can reset it in case something // Store how much we've pushed at this point so we can reset it in case something
// suspended partially through writing something. // suspended partially through writing something.
@ -3551,7 +3527,7 @@ function renderNode(
task.keyPath = previousKeyPath; task.keyPath = previousKeyPath;
task.treeContext = previousTreeContext; task.treeContext = previousTreeContext;
task.componentStack = previousComponentStack; task.componentStack = previousComponentStack;
if (__DEV__ && enableOwnerStacks) { if (__DEV__) {
task.debugTask = previousDebugTask; task.debugTask = previousDebugTask;
} }
// Restore all active ReactContexts to what they were before. // Restore all active ReactContexts to what they were before.
@ -3584,7 +3560,7 @@ function renderNode(
task.keyPath = previousKeyPath; task.keyPath = previousKeyPath;
task.treeContext = previousTreeContext; task.treeContext = previousTreeContext;
task.componentStack = previousComponentStack; task.componentStack = previousComponentStack;
if (__DEV__ && enableOwnerStacks) { if (__DEV__) {
task.debugTask = previousDebugTask; task.debugTask = previousDebugTask;
} }
// Restore all active ReactContexts to what they were before. // Restore all active ReactContexts to what they were before.
@ -3642,7 +3618,7 @@ function renderNode(
task.keyPath = previousKeyPath; task.keyPath = previousKeyPath;
task.treeContext = previousTreeContext; task.treeContext = previousTreeContext;
task.componentStack = previousComponentStack; task.componentStack = previousComponentStack;
if (__DEV__ && enableOwnerStacks) { if (__DEV__) {
task.debugTask = previousDebugTask; task.debugTask = previousDebugTask;
} }
// Restore all active ReactContexts to what they were before. // Restore all active ReactContexts to what they were before.
@ -3681,7 +3657,7 @@ function renderNode(
task.keyPath = previousKeyPath; task.keyPath = previousKeyPath;
task.treeContext = previousTreeContext; task.treeContext = previousTreeContext;
task.componentStack = previousComponentStack; task.componentStack = previousComponentStack;
if (__DEV__ && enableOwnerStacks) { if (__DEV__) {
task.debugTask = previousDebugTask; task.debugTask = previousDebugTask;
} }
// Restore all active ReactContexts to what they were before. // Restore all active ReactContexts to what they were before.
@ -3714,7 +3690,7 @@ function renderNode(
task.keyPath = previousKeyPath; task.keyPath = previousKeyPath;
task.treeContext = previousTreeContext; task.treeContext = previousTreeContext;
task.componentStack = previousComponentStack; task.componentStack = previousComponentStack;
if (__DEV__ && enableOwnerStacks) { if (__DEV__) {
task.debugTask = previousDebugTask; task.debugTask = previousDebugTask;
} }
// Restore all active ReactContexts to what they were before. // Restore all active ReactContexts to what they were before.
@ -4421,14 +4397,14 @@ function retryRenderTask(
request, request,
postponeInstance.message, postponeInstance.message,
thrownInfo, thrownInfo,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
} else { } else {
logRecoverableError( logRecoverableError(
request, request,
x, x,
thrownInfo, thrownInfo,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
} }
@ -4464,7 +4440,7 @@ function retryRenderTask(
request, request,
postponeInstance.message, postponeInstance.message,
postponeInfo, postponeInfo,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
trackPostpone(request, trackedPostpones, task, segment); trackPostpone(request, trackedPostpones, task, segment);
finishedTask(request, task.blockedBoundary, segment); finishedTask(request, task.blockedBoundary, segment);
@ -4481,7 +4457,7 @@ function retryRenderTask(
task.blockedBoundary, task.blockedBoundary,
x, x,
errorInfo, errorInfo,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
return; return;
} finally { } finally {
@ -4560,7 +4536,7 @@ function retryReplayTask(request: Request, task: ReplayTask): void {
errorInfo, errorInfo,
task.replay.nodes, task.replay.nodes,
task.replay.slots, task.replay.slots,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
request.pendingRootTasks--; request.pendingRootTasks--;
if (request.pendingRootTasks === 0) { if (request.pendingRootTasks === 0) {

View File

@ -17,7 +17,6 @@ import {
enablePostpone, enablePostpone,
enableHalt, enableHalt,
enableTaint, enableTaint,
enableOwnerStacks,
enableProfilerTimer, enableProfilerTimer,
enableComponentPerformanceTrack, enableComponentPerformanceTrack,
} from 'shared/ReactFeatureFlags'; } from 'shared/ReactFeatureFlags';
@ -254,15 +253,11 @@ if (__DEV__ && typeof console === 'object' && console !== null) {
function getCurrentStackInDEV(): string { function getCurrentStackInDEV(): string {
if (__DEV__) { if (__DEV__) {
if (enableOwnerStacks) { const owner: null | ReactComponentInfo = resolveOwner();
const owner: null | ReactComponentInfo = resolveOwner(); if (owner === null) {
if (owner === null) { return '';
return '';
}
return getOwnerStackByComponentInfoInDev(owner);
} }
// We don't have Parent Stacks in Flight. return getOwnerStackByComponentInfoInDev(owner);
return '';
} }
return ''; return '';
} }
@ -624,8 +619,8 @@ function serializeThenable(
task.implicitSlot, task.implicitSlot,
request.abortableTasks, request.abortableTasks,
__DEV__ ? task.debugOwner : null, __DEV__ ? task.debugOwner : null,
__DEV__ && enableOwnerStacks ? task.debugStack : null, __DEV__ ? task.debugStack : null,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
if (__DEV__) { if (__DEV__) {
// If this came from Flight, forward any debug info into this new row. // If this came from Flight, forward any debug info into this new row.
@ -744,8 +739,8 @@ function serializeReadableStream(
task.implicitSlot, task.implicitSlot,
request.abortableTasks, request.abortableTasks,
__DEV__ ? task.debugOwner : null, __DEV__ ? task.debugOwner : null,
__DEV__ && enableOwnerStacks ? task.debugStack : null, __DEV__ ? task.debugStack : null,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
request.abortableTasks.delete(streamTask); request.abortableTasks.delete(streamTask);
@ -834,8 +829,8 @@ function serializeAsyncIterable(
task.implicitSlot, task.implicitSlot,
request.abortableTasks, request.abortableTasks,
__DEV__ ? task.debugOwner : null, __DEV__ ? task.debugOwner : null,
__DEV__ && enableOwnerStacks ? task.debugStack : null, __DEV__ ? task.debugStack : null,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
request.abortableTasks.delete(streamTask); request.abortableTasks.delete(streamTask);
@ -1035,23 +1030,21 @@ function callWithDebugContextInDEV<A, T>(
key: null, key: null,
owner: task.debugOwner, owner: task.debugOwner,
}; };
if (enableOwnerStacks) { // $FlowFixMe[cannot-write]
// $FlowFixMe[cannot-write] componentDebugInfo.stack =
componentDebugInfo.stack = task.debugStack === null
task.debugStack === null ? null
? null : filterStackTrace(request, task.debugStack, 1);
: filterStackTrace(request, task.debugStack, 1); // $FlowFixMe[cannot-write]
// $FlowFixMe[cannot-write] componentDebugInfo.debugStack = task.debugStack;
componentDebugInfo.debugStack = task.debugStack; // $FlowFixMe[cannot-write]
// $FlowFixMe[cannot-write] componentDebugInfo.debugTask = task.debugTask;
componentDebugInfo.debugTask = task.debugTask;
}
const debugTask = task.debugTask; const debugTask = task.debugTask;
// We don't need the async component storage context here so we only set the // We don't need the async component storage context here so we only set the
// synchronous tracking of owner. // synchronous tracking of owner.
setCurrentOwner(componentDebugInfo); setCurrentOwner(componentDebugInfo);
try { try {
if (enableOwnerStacks && debugTask) { if (debugTask) {
return debugTask.run(callback.bind(null, arg)); return debugTask.run(callback.bind(null, arg));
} }
return callback(arg); return callback(arg);
@ -1238,22 +1231,18 @@ function renderFunctionComponent<Props>(
key: key, key: key,
owner: task.debugOwner, owner: task.debugOwner,
}: ReactComponentInfo); }: ReactComponentInfo);
if (enableOwnerStacks) { // $FlowFixMe[cannot-write]
// $FlowFixMe[cannot-write] componentDebugInfo.stack =
componentDebugInfo.stack = task.debugStack === null
task.debugStack === null ? null
? null : filterStackTrace(request, task.debugStack, 1);
: filterStackTrace(request, task.debugStack, 1); // $FlowFixMe[cannot-write]
// $FlowFixMe[cannot-write] componentDebugInfo.props = props;
componentDebugInfo.props = props; // $FlowFixMe[cannot-write]
// $FlowFixMe[cannot-write] componentDebugInfo.debugStack = task.debugStack;
componentDebugInfo.debugStack = task.debugStack; // $FlowFixMe[cannot-write]
// $FlowFixMe[cannot-write] componentDebugInfo.debugTask = task.debugTask;
componentDebugInfo.debugTask = task.debugTask;
} else {
// $FlowFixMe[cannot-write]
componentDebugInfo.props = props;
}
// We outline this model eagerly so that we can refer to by reference as an owner. // We outline this model eagerly so that we can refer to by reference as an owner.
// If we had a smarter way to dedupe we might not have to do this if there ends up // If we had a smarter way to dedupe we might not have to do this if there ends up
// being no references to this as an owner. // being no references to this as an owner.
@ -1271,14 +1260,14 @@ function renderFunctionComponent<Props>(
// We've emitted the latest environment for this task so we track that. // We've emitted the latest environment for this task so we track that.
task.environmentName = componentEnv; task.environmentName = componentEnv;
if (enableOwnerStacks && validated === 2) { if (validated === 2) {
warnForMissingKey(request, key, componentDebugInfo, task.debugTask); warnForMissingKey(request, key, componentDebugInfo, task.debugTask);
} }
} }
prepareToUseHooksForComponent(prevThenableState, componentDebugInfo); prepareToUseHooksForComponent(prevThenableState, componentDebugInfo);
if (supportsComponentStorage) { if (supportsComponentStorage) {
// Run the component in an Async Context that tracks the current owner. // Run the component in an Async Context that tracks the current owner.
if (enableOwnerStacks && task.debugTask) { if (task.debugTask) {
result = task.debugTask.run( result = task.debugTask.run(
// $FlowFixMe[method-unbinding] // $FlowFixMe[method-unbinding]
componentStorage.run.bind( componentStorage.run.bind(
@ -1300,7 +1289,7 @@ function renderFunctionComponent<Props>(
); );
} }
} else { } else {
if (enableOwnerStacks && task.debugTask) { if (task.debugTask) {
result = task.debugTask.run( result = task.debugTask.run(
callComponentInDEV.bind(null, Component, props, componentDebugInfo), callComponentInDEV.bind(null, Component, props, componentDebugInfo),
); );
@ -1387,7 +1376,7 @@ function warnForMissingKey(
if (supportsComponentStorage) { if (supportsComponentStorage) {
// Run the component in an Async Context that tracks the current owner. // Run the component in an Async Context that tracks the current owner.
if (enableOwnerStacks && debugTask) { if (debugTask) {
debugTask.run( debugTask.run(
// $FlowFixMe[method-unbinding] // $FlowFixMe[method-unbinding]
componentStorage.run.bind( componentStorage.run.bind(
@ -1409,7 +1398,7 @@ function warnForMissingKey(
); );
} }
} else { } else {
if (enableOwnerStacks && debugTask) { if (debugTask) {
debugTask.run( debugTask.run(
callComponentInDEV.bind(null, logKeyError, null, componentDebugInfo), callComponentInDEV.bind(null, logKeyError, null, componentDebugInfo),
); );
@ -1445,23 +1434,15 @@ function renderFragment(
// We have a Server Component that specifies a key but we're now splitting // We have a Server Component that specifies a key but we're now splitting
// the tree using a fragment. // the tree using a fragment.
const fragment = __DEV__ const fragment = __DEV__
? enableOwnerStacks ? [
? [ REACT_ELEMENT_TYPE,
REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE,
REACT_FRAGMENT_TYPE, task.keyPath,
task.keyPath, {children},
{children}, null,
null, null,
null, 0,
0, ]
]
: [
REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE,
task.keyPath,
{children},
null,
]
: [REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE, task.keyPath, {children}]; : [REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE, task.keyPath, {children}];
if (!task.implicitSlot) { if (!task.implicitSlot) {
// If this was keyed inside a set. I.e. the outer Server Component was keyed // If this was keyed inside a set. I.e. the outer Server Component was keyed
@ -1517,23 +1498,15 @@ function renderAsyncFragment(
// We have a Server Component that specifies a key but we're now splitting // We have a Server Component that specifies a key but we're now splitting
// the tree using a fragment. // the tree using a fragment.
const fragment = __DEV__ const fragment = __DEV__
? enableOwnerStacks ? [
? [ REACT_ELEMENT_TYPE,
REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE,
REACT_FRAGMENT_TYPE, task.keyPath,
task.keyPath, {children},
{children}, null,
null, null,
null, 0,
0, ]
]
: [
REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE,
task.keyPath,
{children},
null,
]
: [REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE, task.keyPath, {children}]; : [REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE, task.keyPath, {children}];
if (!task.implicitSlot) { if (!task.implicitSlot) {
// If this was keyed inside a set. I.e. the outer Server Component was keyed // If this was keyed inside a set. I.e. the outer Server Component was keyed
@ -1586,19 +1559,17 @@ function renderClientElement(
} }
} }
const element = __DEV__ const element = __DEV__
? enableOwnerStacks ? [
? [ REACT_ELEMENT_TYPE,
REACT_ELEMENT_TYPE, type,
type, key,
key, props,
props, task.debugOwner,
task.debugOwner, task.debugStack === null
task.debugStack === null ? null
? null : filterStackTrace(request, task.debugStack, 1),
: filterStackTrace(request, task.debugStack, 1), validated,
validated, ]
]
: [REACT_ELEMENT_TYPE, type, key, props, task.debugOwner]
: [REACT_ELEMENT_TYPE, type, key, props]; : [REACT_ELEMENT_TYPE, type, key, props];
if (task.implicitSlot && key !== null) { if (task.implicitSlot && key !== null) {
// The root Server Component had no key so it was in an implicit slot. // The root Server Component had no key so it was in an implicit slot.
@ -1626,8 +1597,8 @@ function outlineTask(request: Request, task: Task): ReactJSONValue {
task.implicitSlot, task.implicitSlot,
request.abortableTasks, request.abortableTasks,
__DEV__ ? task.debugOwner : null, __DEV__ ? task.debugOwner : null,
__DEV__ && enableOwnerStacks ? task.debugStack : null, __DEV__ ? task.debugStack : null,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
retryTask(request, newTask); retryTask(request, newTask);
@ -1694,7 +1665,7 @@ function renderElement(
} else if (type === REACT_FRAGMENT_TYPE && key === null) { } else if (type === REACT_FRAGMENT_TYPE && key === null) {
// For key-less fragments, we add a small optimization to avoid serializing // For key-less fragments, we add a small optimization to avoid serializing
// it as a wrapper. // it as a wrapper.
if (__DEV__ && enableOwnerStacks && validated === 2) { if (__DEV__ && validated === 2) {
// Create a fake owner node for the error stack. // Create a fake owner node for the error stack.
const componentDebugInfo: ReactComponentInfo = { const componentDebugInfo: ReactComponentInfo = {
name: 'Fragment', name: 'Fragment',
@ -1900,10 +1871,8 @@ function createTask(
if (__DEV__) { if (__DEV__) {
task.environmentName = request.environmentName(); task.environmentName = request.environmentName();
task.debugOwner = debugOwner; task.debugOwner = debugOwner;
if (enableOwnerStacks) { task.debugStack = debugStack;
task.debugStack = debugStack; task.debugTask = debugTask;
task.debugTask = debugTask;
}
} }
abortSet.add(task); abortSet.add(task);
return task; return task;
@ -2348,8 +2317,8 @@ function renderModel(
task.implicitSlot, task.implicitSlot,
request.abortableTasks, request.abortableTasks,
__DEV__ ? task.debugOwner : null, __DEV__ ? task.debugOwner : null,
__DEV__ && enableOwnerStacks ? task.debugStack : null, __DEV__ ? task.debugStack : null,
__DEV__ && enableOwnerStacks ? task.debugTask : null, __DEV__ ? task.debugTask : null,
); );
const ping = newTask.ping; const ping = newTask.ping;
(x: any).then(ping, ping); (x: any).then(ping, ping);
@ -2487,10 +2456,8 @@ function renderModelDestructive(
if (__DEV__) { if (__DEV__) {
task.debugOwner = element._owner; task.debugOwner = element._owner;
if (enableOwnerStacks) { task.debugStack = element._debugStack;
task.debugStack = element._debugStack; task.debugTask = element._debugTask;
task.debugTask = element._debugTask;
}
// TODO: Pop this. Since we currently don't have a point where we can pop the stack // TODO: Pop this. Since we currently don't have a point where we can pop the stack
// this debug information will be used for errors inside sibling properties that // this debug information will be used for errors inside sibling properties that
// are not elements. Leading to the wrong attribution on the server. We could fix // are not elements. Leading to the wrong attribution on the server. We could fix
@ -2506,7 +2473,7 @@ function renderModelDestructive(
element.key, element.key,
ref, ref,
props, props,
__DEV__ && enableOwnerStacks ? element._store.validated : 0, __DEV__ ? element._store.validated : 0,
); );
if ( if (
typeof newChild === 'object' && typeof newChild === 'object' &&
@ -3291,10 +3258,8 @@ function outlineComponentInfo(
key: componentInfo.key, key: componentInfo.key,
owner: componentInfo.owner, owner: componentInfo.owner,
}; };
if (enableOwnerStacks) { // $FlowFixMe[cannot-write]
// $FlowFixMe[cannot-write] componentDebugInfo.stack = componentInfo.stack;
componentDebugInfo.stack = componentInfo.stack;
}
// Ensure we serialize props after the stack to favor the stack being complete. // Ensure we serialize props after the stack to favor the stack being complete.
// $FlowFixMe[cannot-write] // $FlowFixMe[cannot-write]
componentDebugInfo.props = componentInfo.props; componentDebugInfo.props = componentInfo.props;
@ -3435,33 +3400,23 @@ function renderConsoleValue(
doNotLimit.add(element._owner); doNotLimit.add(element._owner);
} }
if (enableOwnerStacks) { let debugStack: null | ReactStackTrace = null;
let debugStack: null | ReactStackTrace = null; if (element._debugStack != null) {
if (element._debugStack != null) { // Outline the debug stack so that it doesn't get cut off.
// Outline the debug stack so that it doesn't get cut off. debugStack = filterStackTrace(request, element._debugStack, 1);
debugStack = filterStackTrace(request, element._debugStack, 1); doNotLimit.add(debugStack);
doNotLimit.add(debugStack); for (let i = 0; i < debugStack.length; i++) {
for (let i = 0; i < debugStack.length; i++) { doNotLimit.add(debugStack[i]);
doNotLimit.add(debugStack[i]);
}
} }
return [
REACT_ELEMENT_TYPE,
element.type,
element.key,
element.props,
element._owner,
debugStack,
element._store.validated,
];
} }
return [ return [
REACT_ELEMENT_TYPE, REACT_ELEMENT_TYPE,
element.type, element.type,
element.key, element.key,
element.props, element.props,
element._owner, element._owner,
debugStack,
element._store.validated,
]; ];
} }
} }

View File

@ -7,8 +7,8 @@
* @flow * @flow
*/ */
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import {captureOwnerStack as captureOwnerStackImpl} from './src/ReactClient'; import {captureOwnerStack as captureOwnerStackImpl} from './src/ReactClient';
export { export {
__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
__COMPILER_RUNTIME, __COMPILER_RUNTIME,
@ -72,7 +72,7 @@ export {useMemoCache as c} from './src/ReactHooks';
// Only export captureOwnerStack in development. // Only export captureOwnerStack in development.
let captureOwnerStack: ?() => null | string; let captureOwnerStack: ?() => null | string;
if (__DEV__ && enableOwnerStacks) { if (__DEV__) {
captureOwnerStack = captureOwnerStackImpl; captureOwnerStack = captureOwnerStackImpl;
} }

View File

@ -7,18 +7,17 @@
* @flow * @flow
*/ */
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals'; import ReactSharedInternals from 'shared/ReactSharedInternals';
export function captureOwnerStack(): null | string { export function captureOwnerStack(): null | string {
if (!enableOwnerStacks || !__DEV__) { if (__DEV__) {
return null; const getCurrentStack = ReactSharedInternals.getCurrentStack;
if (getCurrentStack === null) {
return null;
}
// The current stack will be the owner stack which it is always here.
return getCurrentStack();
} }
const getCurrentStack = ReactSharedInternals.getCurrentStack;
if (getCurrentStack === null) { return null;
return null;
}
// The current stack will be the owner stack if enableOwnerStacks is true
// which it is always here. Otherwise it's the parent stack.
return getCurrentStack();
} }

View File

@ -10,7 +10,6 @@
export {default as __SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE} from './ReactSharedInternalsServer'; export {default as __SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE} from './ReactSharedInternalsServer';
import {forEach, map, count, toArray, only} from './ReactChildren'; import {forEach, map, count, toArray, only} from './ReactChildren';
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import {captureOwnerStack as captureOwnerStackImpl} from './ReactOwnerStack'; import {captureOwnerStack as captureOwnerStackImpl} from './ReactOwnerStack';
import { import {
REACT_FRAGMENT_TYPE, REACT_FRAGMENT_TYPE,
@ -39,9 +38,8 @@ const Children = {
only, only,
}; };
// Only export captureOwnerStack if the flag is on, to support feature detection.
let captureOwnerStack: ?() => null | string; let captureOwnerStack: ?() => null | string;
if (__DEV__ && enableOwnerStacks) { if (__DEV__) {
captureOwnerStack = captureOwnerStackImpl; captureOwnerStack = captureOwnerStackImpl;
} }

View File

@ -333,16 +333,6 @@ describe('ReactChildren', () => {
} }
const instance = <div>{threeDivIterable}</div>; const instance = <div>{threeDivIterable}</div>;
assertConsoleErrorDev(
// With the flag on this doesn't warn eagerly but only when rendered
gate(flag => flag.enableOwnerStacks)
? []
: [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <div>. See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
],
);
React.Children.forEach(instance.props.children, callback, context); React.Children.forEach(instance.props.children, callback, context);
@ -369,8 +359,7 @@ describe('ReactChildren', () => {
'Each child in a list should have a unique "key" prop.\n\n' + 'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <div>. It was passed a child from div.' + 'Check the top-level render call using <div>. It was passed a child from div.' +
' See https://react.dev/link/warning-keys for more information.\n' + ' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)' + ' in div (at **)',
(gate(flag => flag.enableOwnerStacks) ? '' : '\n in div (at **)'),
]); ]);
}); });
@ -894,22 +883,13 @@ describe('ReactChildren', () => {
</ComponentRenderingMappedChildren>, </ComponentRenderingMappedChildren>,
); );
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'Each child in a list should have a unique "key" prop.\n\n' +
? [ 'Check the render method of `ComponentRenderingMappedChildren`.' +
'Each child in a list should have a unique "key" prop.\n\n' + ' See https://react.dev/link/warning-keys for more information.\n' +
'Check the render method of `ComponentRenderingMappedChildren`.' + ' in div (at **)\n' +
' See https://react.dev/link/warning-keys for more information.\n' + ' in **/ReactChildren-test.js:**:** (at **)',
' in div (at **)\n' + ]);
' in **/ReactChildren-test.js:**:** (at **)',
]
: [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ComponentRenderingMappedChildren>.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
],
);
}); });
it('does not warn for mapped static children without keys', async () => { it('does not warn for mapped static children without keys', async () => {
@ -953,21 +933,12 @@ describe('ReactChildren', () => {
</ComponentRenderingClonedChildren>, </ComponentRenderingClonedChildren>,
); );
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'Each child in a list should have a unique "key" prop.\n\n' +
? [ 'Check the render method of `ComponentRenderingClonedChildren`.' +
'Each child in a list should have a unique "key" prop.\n\n' + ' See https://react.dev/link/warning-keys for more information.\n' +
'Check the render method of `ComponentRenderingClonedChildren`.' + ' in div (at **)',
' See https://react.dev/link/warning-keys for more information.\n' + ]);
' in div (at **)',
]
: [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ComponentRenderingClonedChildren>.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
],
);
}); });
it('does not warn for cloned static children without keys', async () => { it('does not warn for cloned static children without keys', async () => {
@ -1005,21 +976,12 @@ describe('ReactChildren', () => {
</ComponentRenderingFlattenedChildren>, </ComponentRenderingFlattenedChildren>,
); );
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'Each child in a list should have a unique "key" prop.\n\n' +
? [ 'Check the render method of `ComponentRenderingFlattenedChildren`.' +
'Each child in a list should have a unique "key" prop.\n\n' + ' See https://react.dev/link/warning-keys for more information.\n' +
'Check the render method of `ComponentRenderingFlattenedChildren`.' + ' in div (at **)',
' See https://react.dev/link/warning-keys for more information.\n' + ]);
' in div (at **)',
]
: [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ComponentRenderingFlattenedChildren>.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
],
);
}); });
it('does not warn for flattened static children without keys', async () => { it('does not warn for flattened static children without keys', async () => {

View File

@ -266,26 +266,14 @@ describe 'ReactCoffeeScriptClass', ->
test React.createElement(Outer), 'SPAN', 'foo' test React.createElement(Outer), 'SPAN', 'foo'
if featureFlags.enableOwnerStacks assertConsoleErrorDev([
assertConsoleErrorDev([ 'Outer uses the legacy childContextTypes API which will soon be removed.
'Outer uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + ' in Outer (at **)',
' in Outer (at **)', 'Foo uses the legacy contextTypes API which will soon be removed.
'Foo uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + ' in Outer (at **)',
' in Outer (at **)', ]);
]);
else
assertConsoleErrorDev([
'Outer uses the legacy childContextTypes API which will soon be removed.
Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
' in Outer (at **)',
'Foo uses the legacy contextTypes API which will soon be removed.
Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in Foo (at **)\n' +
' in Outer (at **)',
]);
it 'renders only once when setting state in componentWillMount', -> it 'renders only once when setting state in componentWillMount', ->
renderCount = 0 renderCount = 0
@ -578,24 +566,13 @@ describe 'ReactCoffeeScriptClass', ->
React.createElement Bar React.createElement Bar
test React.createElement(Foo), 'DIV', 'bar-through-context' test React.createElement(Foo), 'DIV', 'bar-through-context'
if featureFlags.enableOwnerStacks assertConsoleErrorDev [
assertConsoleErrorDev [ 'Foo uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.
'Foo uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
(https://react.dev/link/legacy-context)\n' + ' in Foo (at **)',
' in Foo (at **)', 'Bar uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.
'Bar uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(https://react.dev/link/legacy-context)\n' + ' in Foo (at **)'
' in Foo (at **)' ]
]
else
assertConsoleErrorDev [
'Foo uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.
(https://react.dev/link/legacy-context)\n' +
' in Foo (at **)',
'Bar uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.
(https://react.dev/link/legacy-context)\n' +
' in Bar (at **)\n' +
' in Foo (at **)'
]
undefined undefined

View File

@ -78,9 +78,7 @@ describe('ReactContextValidator', () => {
' in ComponentInFooBarContext (at **)', ' in ComponentInFooBarContext (at **)',
'Component uses the legacy contextTypes API which will soon be removed. ' + 'Component uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate(flags => flags.enableOwnerStacks) ' in ComponentInFooBarContext (at **)',
? ' in ComponentInFooBarContext (at **)'
: ' in Component (at **)'),
]); ]);
expect(instance.childRef.current.context).toEqual({foo: 'abc'}); expect(instance.childRef.current.context).toEqual({foo: 'abc'});
}); });
@ -159,9 +157,7 @@ describe('ReactContextValidator', () => {
' in Parent (at **)', ' in Parent (at **)',
'Component uses the legacy contextTypes API which will soon be removed. ' + 'Component uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate(flags => flags.enableOwnerStacks) ' in Parent (at **)',
? ' in Parent (at **)'
: ' in Component (at **)'),
]); ]);
expect(constructorContext).toEqual({foo: 'abc'}); expect(constructorContext).toEqual({foo: 'abc'});
@ -282,21 +278,12 @@ describe('ReactContextValidator', () => {
' in ParentContextProvider (at **)', ' in ParentContextProvider (at **)',
'MiddleMissingContext uses the legacy childContextTypes API which will soon be removed. ' + 'MiddleMissingContext uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in MiddleMissingContext (at **)\n') +
' in ParentContextProvider (at **)', ' in ParentContextProvider (at **)',
'MiddleMissingContext.childContextTypes is specified but there is no getChildContext() method on the instance. ' + 'MiddleMissingContext.childContextTypes is specified but there is no getChildContext() method on the instance. ' +
'You can either define getChildContext() on MiddleMissingContext or remove childContextTypes from it.\n' + 'You can either define getChildContext() on MiddleMissingContext or remove childContextTypes from it.\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in MiddleMissingContext (at **)\n') +
' in ParentContextProvider (at **)', ' in ParentContextProvider (at **)',
'ChildContextConsumer uses the legacy contextTypes API which will soon be removed. ' + 'ChildContextConsumer uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in ChildContextConsumer (at **)\n') +
' in MiddleMissingContext (at **)\n' + ' in MiddleMissingContext (at **)\n' +
' in ParentContextProvider (at **)', ' in ParentContextProvider (at **)',
]); ]);

View File

@ -77,13 +77,7 @@ describe('ReactCreateElement', () => {
'in `undefined` being returned. If you need to access the same ' + 'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' + 'value within the child component, you should pass it as a different ' +
'prop. (https://react.dev/link/special-props)\n' + 'prop. (https://react.dev/link/special-props)\n' +
(gate(flags => flags.enableOwnerStacks) ' in Parent (at **)',
? [' in Parent (at **)']
: [
' in Child (at **)\n' +
' in div (at **)\n' +
' in Parent (at **)',
]),
]); ]);
}); });

View File

@ -46,10 +46,7 @@ describe('ReactCreateRef', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'Unexpected ref object provided for div. ' + 'Unexpected ref object provided for div. ' +
'Use either a ref-setter function or React.createRef().\n' + 'Use either a ref-setter function or React.createRef().\n' +
' in div (at **)' + ' in div (at **)',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in Wrapper (at **)'),
]); ]);
ReactDOM.flushSync(() => { ReactDOM.flushSync(() => {
@ -62,10 +59,7 @@ describe('ReactCreateRef', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'Unexpected ref object provided for ExampleComponent. ' + 'Unexpected ref object provided for ExampleComponent. ' +
'Use either a ref-setter function or React.createRef().\n' + 'Use either a ref-setter function or React.createRef().\n' +
' in ExampleComponent (at **)' + ' in ExampleComponent (at **)',
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in Wrapper (at **)'),
]); ]);
}); });
}); });

View File

@ -305,9 +305,6 @@ describe('ReactES6Class', () => {
' in Outer (at **)', ' in Outer (at **)',
'Foo uses the legacy contextTypes API which will soon be removed. ' + 'Foo uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Foo (at **)\n') +
' in Outer (at **)', ' in Outer (at **)',
]); ]);
}); });
@ -638,9 +635,6 @@ describe('ReactES6Class', () => {
' in Foo (at **)', ' in Foo (at **)',
'Bar uses the legacy contextTypes API which will soon be removed. ' + 'Bar uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Bar (at **)\n') +
' in Foo (at **)', ' in Foo (at **)',
]); ]);
}); });

View File

@ -46,19 +46,11 @@ describe('ReactElementValidator', () => {
]), ]),
), ),
); );
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'Each child in a list should have a unique "key" prop.\n\n' +
? [ 'Check the render method of `ComponentClass`. See https://react.dev/link/warning-keys for more information.\n' +
'Each child in a list should have a unique "key" prop.\n\n' + ' in ComponentClass (at **)',
'Check the render method of `ComponentClass`. See https://react.dev/link/warning-keys for more information.\n' + ]);
' in ComponentClass (at **)',
]
: [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ComponentClass>. See https://react.dev/link/warning-keys for more information.\n' +
' in ComponentClass (at **)',
],
);
}); });
it('warns for keys for arrays of elements with owner info', async () => { it('warns for keys for arrays of elements with owner info', async () => {
@ -83,18 +75,10 @@ describe('ReactElementValidator', () => {
await act(() => root.render(React.createElement(ComponentWrapper))); await act(() => root.render(React.createElement(ComponentWrapper)));
assertConsoleErrorDev([ assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.' + 'Each child in a list should have a unique "key" prop.' +
'\n\nCheck the render method of `' + '\n\nCheck the render method of `ComponentClass`. ' +
(gate(flags => flags.enableOwnerStacks)
? 'ComponentClass'
: 'InnerClass') +
'`. ' +
'It was passed a child from ComponentWrapper. ' + 'It was passed a child from ComponentWrapper. ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
(gate(flags => flags.enableOwnerStacks) ' in ComponentWrapper (at **)',
? ' in ComponentWrapper (at **)'
: ' in ComponentClass (at **)\n' +
' in InnerClass (at **)\n' +
' in ComponentWrapper (at **)'),
]); ]);
}); });
@ -109,16 +93,12 @@ describe('ReactElementValidator', () => {
const root = ReactDOMClient.createRoot(document.createElement('div')); const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => root.render(<Anonymous>{divs}</Anonymous>)); await act(() => root.render(<Anonymous>{divs}</Anonymous>));
assertConsoleErrorDev([ assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) // For owner stacks the parent being validated is the div.
? // For owner stacks the parent being validated is the div. 'Each child in a list should have a unique ' +
'Each child in a list should have a unique ' + '"key" prop.' +
'"key" prop.' + '\n\nCheck the top-level render call using <div>. ' +
'\n\nCheck the top-level render call using <div>. ' + 'See https://react.dev/link/warning-keys for more information.\n' +
'See https://react.dev/link/warning-keys for more information.\n' + ' in div (at **)',
' in div (at **)'
: 'Each child in a list should have a unique ' +
'"key" prop. See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]); ]);
}); });
@ -158,9 +138,6 @@ describe('ReactElementValidator', () => {
'https://react.dev/link/warning-keys for more information.\n' + 'https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)\n' + ' in div (at **)\n' +
' in Component (at **)\n' + ' in Component (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Parent (at **)\n') +
' in GrandParent (at **)', ' in GrandParent (at **)',
]); ]);
}); });
@ -206,35 +183,12 @@ describe('ReactElementValidator', () => {
await act(() => await act(() =>
root.render(React.createElement(ComponentClass, null, iterable)), root.render(React.createElement(ComponentClass, null, iterable)),
); );
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flag => flag.enableOwnerStacks) 'Each child in a list should have a unique "key" prop.\n\n' +
? [ 'Check the render method of `ComponentClass`. It was passed a child from div. ' +
'Each child in a list should have a unique "key" prop.\n\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
'Check the render method of `ComponentClass`. It was passed a child from div. ' + ' in ComponentClass (at **)',
'See https://react.dev/link/warning-keys for more information.\n' + ]);
' in ComponentClass (at **)',
]
: // Since each pass generates a new element, it doesn't get marked as
// validated and it gets rechecked each time.
[
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ComponentClass>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in ComponentClass (at **)',
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `ComponentClass`. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in ComponentClass (at **)\n' +
' in ComponentClass (at **)',
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `ComponentClass`. It was passed a child from div. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in ComponentClass (at **)\n' +
' in div (at **)\n' +
' in ComponentClass (at **)',
],
);
}); });
it('does not warns for arrays of elements with keys', () => { it('does not warns for arrays of elements with keys', () => {
@ -373,13 +327,6 @@ describe('ReactElementValidator', () => {
]; ];
for (let i = 0; i < cases.length; i++) { for (let i = 0; i < cases.length; i++) {
await act(async () => root.render(cases[i][0]())); await act(async () => root.render(cases[i][0]()));
assertConsoleErrorDev(
gate(flag => flag.enableOwnerStacks)
? // We don't need these extra warnings because we already have the errors.
[]
: [cases[i][1]],
{withoutStack: true},
);
} }
expect(errors).toEqual( expect(errors).toEqual(
@ -468,21 +415,6 @@ describe('ReactElementValidator', () => {
'or a class/function (for composite components) but got: null.' + 'or a class/function (for composite components) but got: null.' +
(__DEV__ ? '\n\nCheck the render method of `ParentComp`.' : ''), (__DEV__ ? '\n\nCheck the render method of `ParentComp`.' : ''),
); );
assertConsoleErrorDev(
gate(flag => flag.enableOwnerStacks)
? // We don't need these extra warnings because we already have the errors.
[]
: [
'React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: null.\n' +
' in ParentComp (at **)',
'React.createElement: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: null.\n' +
' in ParentComp (at **)',
],
);
}); });
it('warns for fragments with illegal attributes', async () => { it('warns for fragments with illegal attributes', async () => {
@ -559,18 +491,6 @@ describe('ReactElementValidator', () => {
it('does not blow up on key warning with undefined type', () => { it('does not blow up on key warning with undefined type', () => {
const Foo = undefined; const Foo = undefined;
void (<Foo>{[<div />]}</Foo>); void (<Foo>{[<div />]}</Foo>);
assertConsoleErrorDev(
gate(flags => flags.enableOwnerStacks)
? []
: [
'React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' +
"component from the file it's defined in, or you might have mixed up " +
'default and named imports.',
],
{withoutStack: true},
);
}); });
it('does not call lazy initializers eagerly', () => { it('does not call lazy initializers eagerly', () => {

View File

@ -49,13 +49,9 @@ describe('ReactJSXElementValidator', () => {
root.render(<Component>{[<Component />, <Component />]}</Component>); root.render(<Component>{[<Component />, <Component />]}</Component>);
}); });
assertConsoleErrorDev([ assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks) 'Each child in a list should have a unique "key" prop.\n\n' +
? 'Each child in a list should have a unique "key" prop.\n\n' + 'Check the render method of `Component`. See https://react.dev/link/warning-keys for more information.\n' +
'Check the render method of `Component`. See https://react.dev/link/warning-keys for more information.\n' + ' in Component (at **)',
' in Component (at **)'
: 'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <Component>. See https://react.dev/link/warning-keys for more information.\n' +
' in Component (at **)',
]); ]);
}); });
@ -79,17 +75,9 @@ describe('ReactJSXElementValidator', () => {
}); });
assertConsoleErrorDev([ assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.' + 'Each child in a list should have a unique "key" prop.' +
'\n\nCheck the render method of `' + '\n\nCheck the render method of `Component`. ' +
(gate(flag => flag.enableOwnerStacks)
? 'Component'
: 'InnerComponent') +
'`. ' +
'It was passed a child from ComponentWrapper. See https://react.dev/link/warning-keys for more information.\n' + 'It was passed a child from ComponentWrapper. See https://react.dev/link/warning-keys for more information.\n' +
(gate(flag => flag.enableOwnerStacks) ' in ComponentWrapper (at **)',
? ' in ComponentWrapper (at **)'
: ' in Component (at **)\n' +
' in InnerComponent (at **)\n' +
' in ComponentWrapper (at **)'),
]); ]);
}); });
@ -112,34 +100,12 @@ describe('ReactJSXElementValidator', () => {
await act(() => { await act(() => {
root.render(<Component>{iterable}</Component>); root.render(<Component>{iterable}</Component>);
}); });
assertConsoleErrorDev( assertConsoleErrorDev([
gate(flag => flag.enableOwnerStacks) 'Each child in a list should have a unique "key" prop.\n\n' +
? [ 'Check the render method of `Component`. It was passed a child from div. ' +
'Each child in a list should have a unique "key" prop.\n\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
'Check the render method of `Component`. It was passed a child from div. ' + ' in Component (at **)',
'See https://react.dev/link/warning-keys for more information.\n' + ]);
' in Component (at **)',
]
: // Since each pass generates a new element, it doesn't get marked as
// validated and it gets rechecked each time.
[
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <Component>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Component (at **)',
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `Component`. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Component (at **)\n' +
' in Component (at **)',
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `Component`. It was passed a child from div. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Component (at **)\n' +
' in div (at **)\n' +
' in Component (at **)',
],
);
}); });
it('does not warn for arrays of elements with keys', async () => { it('does not warn for arrays of elements with keys', async () => {

View File

@ -215,11 +215,7 @@ describe('ReactJSXRuntime', () => {
'in `undefined` being returned. If you need to access the same ' + 'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' + 'value within the child component, you should pass it as a different ' +
'prop. (https://react.dev/link/special-props)\n' + 'prop. (https://react.dev/link/special-props)\n' +
(gate(flags => flags.enableOwnerStacks) ' in Parent (at **)',
? ' in Parent (at **)'
: ' in Child (at **)\n' +
' in div (at **)\n' +
' in Parent (at **)'),
]); ]);
}); });
@ -279,9 +275,6 @@ describe('ReactJSXRuntime', () => {
assertConsoleErrorDev([ assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' + 'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `Parent`. See https://react.dev/link/warning-keys for more information.\n' + 'Check the render method of `Parent`. See https://react.dev/link/warning-keys for more information.\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Child (at **)\n') +
' in Parent (at **)', ' in Parent (at **)',
]); ]);
}); });

View File

@ -1042,67 +1042,30 @@ describe('context legacy', () => {
root.render(<Root />); root.render(<Root />);
}); });
if (gate(flags => flags.enableOwnerStacks)) { assertConsoleErrorDev([
assertConsoleErrorDev([ 'LegacyContextProvider uses the legacy childContextTypes API ' +
'LegacyContextProvider uses the legacy childContextTypes API ' + 'which will soon be removed. Use React.createContext() instead. ' +
'which will soon be removed. Use React.createContext() instead. ' + '(https://react.dev/link/legacy-context)' +
'(https://react.dev/link/legacy-context)' + '\n in Root (at **)',
'\n in Root (at **)', 'LegacyContextConsumer uses the legacy contextTypes API which ' +
'LegacyContextConsumer uses the legacy contextTypes API which ' + 'will soon be removed. Use React.createContext() with static ' +
'will soon be removed. Use React.createContext() with static ' + 'contextType instead. (https://react.dev/link/legacy-context)' +
'contextType instead. (https://react.dev/link/legacy-context)' + '\n in LegacyContextProvider (at **)' +
'\n in LegacyContextProvider (at **)' + '\n in Root (at **)',
'\n in Root (at **)', 'FunctionalLegacyContextConsumer uses the legacy contextTypes ' +
'FunctionalLegacyContextConsumer uses the legacy contextTypes ' + 'API which will be removed soon. Use React.createContext() ' +
'API which will be removed soon. Use React.createContext() ' + 'with React.useContext() instead. (https://react.dev/link/legacy-context)' +
'with React.useContext() instead. (https://react.dev/link/legacy-context)' + '\n in LegacyContextProvider (at **)' +
'\n in LegacyContextProvider (at **)' + '\n in Root (at **)',
'\n in Root (at **)', 'Legacy context API has been detected within a strict-mode tree.' +
'Legacy context API has been detected within a strict-mode tree.' + '\n\nThe old API will be supported in all 16.x releases, but applications ' +
'\n\nThe old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.' +
'using it should migrate to the new version.' + '\n\nPlease update the following components: ' +
'\n\nPlease update the following components: ' + 'FunctionalLegacyContextConsumer, LegacyContextConsumer, LegacyContextProvider' +
'FunctionalLegacyContextConsumer, LegacyContextConsumer, LegacyContextProvider' + '\n\nLearn more about this warning here: ' +
'\n\nLearn more about this warning here: ' + 'https://react.dev/link/legacy-context' +
'https://react.dev/link/legacy-context' + '\n in Root (at **)',
'\n in Root (at **)', ]);
]);
} else {
assertConsoleErrorDev([
'LegacyContextProvider uses the legacy childContextTypes API ' +
'which will soon be removed. Use React.createContext() instead. ' +
'(https://react.dev/link/legacy-context)' +
'\n in LegacyContextProvider (at **)' +
'\n in div (at **)' +
'\n in Root (at **)',
'LegacyContextConsumer uses the legacy contextTypes API which ' +
'will soon be removed. Use React.createContext() with static ' +
'contextType instead. (https://react.dev/link/legacy-context)' +
'\n in LegacyContextConsumer (at **)' +
'\n in div (at **)' +
'\n in LegacyContextProvider (at **)' +
'\n in div (at **)' +
'\n in Root (at **)',
'FunctionalLegacyContextConsumer uses the legacy contextTypes ' +
'API which will be removed soon. Use React.createContext() ' +
'with React.useContext() instead. (https://react.dev/link/legacy-context)' +
'\n in FunctionalLegacyContextConsumer (at **)' +
'\n in div (at **)' +
'\n in LegacyContextProvider (at **)' +
'\n in div (at **)' +
'\n in Root (at **)',
'Legacy context API has been detected within a strict-mode tree.' +
'\n\nThe old API will be supported in all 16.x releases, but applications ' +
'using it should migrate to the new version.' +
'\n\nPlease update the following components: ' +
'FunctionalLegacyContextConsumer, LegacyContextConsumer, LegacyContextProvider' +
'\n\nLearn more about this warning here: ' +
'https://react.dev/link/legacy-context' +
'\n in LegacyContextProvider (at **)' +
'\n in div (at **)' +
'\n in Root (at **)',
]);
}
// Dedupe // Dedupe
await act(() => { await act(() => {

View File

@ -528,10 +528,7 @@ describe('ReactTypeScriptClass', function () {
' in ProvideChildContextTypes (at **)', ' in ProvideChildContextTypes (at **)',
'StateBasedOnContext uses the legacy contextTypes API which will soon be removed. ' + 'StateBasedOnContext uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(ReactFeatureFlags.enableOwnerStacks ' in ProvideChildContextTypes.createElement (at **)',
? ' in ProvideChildContextTypes.createElement (at **)'
: ' in StateBasedOnContext (at **)\n') +
' in ProvideChildContextTypes (at **)',
]); ]);
}); });
} }
@ -724,10 +721,7 @@ describe('ReactTypeScriptClass', function () {
' in ProvideContext (at **)', ' in ProvideContext (at **)',
'ReadContext uses the legacy contextTypes API which will soon be removed. ' + 'ReadContext uses the legacy contextTypes API which will soon be removed. ' +
'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
(ReactFeatureFlags.enableOwnerStacks ' in ProvideContext.createElement (at **)',
? ' in ProvideContext.createElement (at **)'
: ' in ReadContext (at **)\n') +
' in ProvideContext (at **)',
]); ]);
}); });
} }

View File

@ -348,14 +348,10 @@ describe('create-react-class-integration', () => {
root.render(<Outer />); root.render(<Outer />);
}); });
assertConsoleErrorDev([ assertConsoleErrorDev([
gate(flags => [
flags.enableOwnerStacks 'Component uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
? [ {withoutStack: true},
'Component uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.', ],
{withoutStack: true},
]
: 'Component uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
),
'Component uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.', 'Component uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
]); ]);
expect(container.firstChild.className).toBe('foo'); expect(container.firstChild.className).toBe('foo');

View File

@ -213,9 +213,7 @@ describe('forwardRef', () => {
'\n\nCheck the top-level render call using <ForwardRef>. It was passed a child from ForwardRef. ' + '\n\nCheck the top-level render call using <ForwardRef>. It was passed a child from ForwardRef. ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
(gate(flags => flags.enableOwnerStacks) ' in **/forwardRef-test.js:**:** (at **)',
? ' in **/forwardRef-test.js:**:** (at **)'
: ' in p (at **)'),
]); ]);
}); });
@ -235,8 +233,7 @@ describe('forwardRef', () => {
'\n\nCheck the top-level render call using <ForwardRef(Inner)>. It was passed a child from ForwardRef(Inner). ' + '\n\nCheck the top-level render call using <ForwardRef(Inner)>. It was passed a child from ForwardRef(Inner). ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Inner (at **)' + ' in Inner (at **)',
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
]); ]);
}); });
@ -257,8 +254,7 @@ describe('forwardRef', () => {
'\n\nCheck the top-level render call using <ForwardRef(Inner)>. It was passed a child from ForwardRef(Inner). ' + '\n\nCheck the top-level render call using <ForwardRef(Inner)>. It was passed a child from ForwardRef(Inner). ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Inner (at **)' + ' in Inner (at **)',
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
]); ]);
}); });
@ -278,8 +274,7 @@ describe('forwardRef', () => {
'\n\nCheck the top-level render call using <Outer>. It was passed a child from Outer. ' + '\n\nCheck the top-level render call using <Outer>. It was passed a child from Outer. ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Outer (at **)' + ' in Outer (at **)',
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
]); ]);
}); });
@ -301,8 +296,7 @@ describe('forwardRef', () => {
'\n\nCheck the top-level render call using <Outer>. It was passed a child from Outer. ' + '\n\nCheck the top-level render call using <Outer>. It was passed a child from Outer. ' +
'See https://react.dev/link/warning-keys for more information.\n' + 'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' + ' in span (at **)\n' +
' in Inner (at **)' + ' in Inner (at **)',
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
]); ]);
}); });

View File

@ -10,25 +10,17 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
import hasOwnProperty from 'shared/hasOwnProperty'; import hasOwnProperty from 'shared/hasOwnProperty';
import assign from 'shared/assign'; import assign from 'shared/assign';
import { import {
getIteratorFn,
REACT_ELEMENT_TYPE, REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE, REACT_FRAGMENT_TYPE,
REACT_LAZY_TYPE, REACT_LAZY_TYPE,
} from 'shared/ReactSymbols'; } from 'shared/ReactSymbols';
import {checkKeyStringCoercion} from 'shared/CheckStringCoercion'; import {checkKeyStringCoercion} from 'shared/CheckStringCoercion';
import isValidElementType from 'shared/isValidElementType';
import isArray from 'shared/isArray'; import isArray from 'shared/isArray';
import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame'; import {disableDefaultPropsExceptForClasses} from 'shared/ReactFeatureFlags';
import {
disableDefaultPropsExceptForClasses,
enableOwnerStacks,
} from 'shared/ReactFeatureFlags';
const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference');
const createTask = const createTask =
// eslint-disable-next-line react-internal/no-production-logging // eslint-disable-next-line react-internal/no-production-logging
__DEV__ && enableOwnerStacks && console.createTask __DEV__ && console.createTask
? // eslint-disable-next-line react-internal/no-production-logging ? // eslint-disable-next-line react-internal/no-production-logging
console.createTask console.createTask
: () => null; : () => null;
@ -261,20 +253,18 @@ function ReactElement(
writable: true, writable: true,
value: null, value: null,
}); });
if (enableOwnerStacks) { Object.defineProperty(element, '_debugStack', {
Object.defineProperty(element, '_debugStack', { configurable: false,
configurable: false, enumerable: false,
enumerable: false, writable: true,
writable: true, value: debugStack,
value: debugStack, });
}); Object.defineProperty(element, '_debugTask', {
Object.defineProperty(element, '_debugTask', { configurable: false,
configurable: false, enumerable: false,
enumerable: false, writable: true,
writable: true, value: debugTask,
value: debugTask, });
});
}
if (Object.freeze) { if (Object.freeze) {
Object.freeze(element.props); Object.freeze(element.props);
Object.freeze(element); Object.freeze(element);
@ -390,8 +380,8 @@ export function jsxProdSignatureRunningInDevWithDynamicChildren(
isStaticChildren, isStaticChildren,
source, source,
self, self,
__DEV__ && enableOwnerStacks ? Error('react-stack-top-frame') : undefined, __DEV__ && Error('react-stack-top-frame'),
__DEV__ && enableOwnerStacks ? createTask(getTaskName(type)) : undefined, __DEV__ && createTask(getTaskName(type)),
); );
} }
} }
@ -412,8 +402,8 @@ export function jsxProdSignatureRunningInDevWithStaticChildren(
isStaticChildren, isStaticChildren,
source, source,
self, self,
__DEV__ && enableOwnerStacks ? Error('react-stack-top-frame') : undefined, __DEV__ && Error('react-stack-top-frame'),
__DEV__ && enableOwnerStacks ? createTask(getTaskName(type)) : undefined, __DEV__ && createTask(getTaskName(type)),
); );
} }
} }
@ -434,8 +424,8 @@ export function jsxDEV(type, config, maybeKey, isStaticChildren, source, self) {
isStaticChildren, isStaticChildren,
source, source,
self, self,
__DEV__ && enableOwnerStacks ? Error('react-stack-top-frame') : undefined, __DEV__ && Error('react-stack-top-frame'),
__DEV__ && enableOwnerStacks ? createTask(getTaskName(type)) : undefined, __DEV__ && createTask(getTaskName(type)),
); );
} }
@ -450,80 +440,37 @@ function jsxDEVImpl(
debugTask, debugTask,
) { ) {
if (__DEV__) { if (__DEV__) {
if (!enableOwnerStacks && !isValidElementType(type)) { // We don't warn for invalid element type here because with owner stacks,
// This is an invalid element type. // we error in the renderer. The renderer is the only one that knows what
// // types are valid for this particular renderer so we let it error there.
// We warn here so that we can get better stack traces but with enableOwnerStacks
// enabled we don't need this because we get good stacks if we error in the
// renderer anyway. The renderer is the only one that knows what types are valid
// for this particular renderer so we let it error there instead.
//
// We warn in this case but don't throw. We expect the element creation to
// succeed and there will likely be errors in render.
let info = '';
if (
type === undefined ||
(typeof type === 'object' &&
type !== null &&
Object.keys(type).length === 0)
) {
info +=
' You likely forgot to export your component from the file ' +
"it's defined in, or you might have mixed up default and named imports.";
}
let typeString; // Skip key warning if the type isn't valid since our key validation logic
if (type === null) { // doesn't expect a non-string/function type and can throw confusing
typeString = 'null'; // errors. We don't want exception behavior to differ between dev and
} else if (isArray(type)) { // prod. (Rendering will throw with a helpful message and as soon as the
typeString = 'array'; // type is fixed, the key warnings will appear.)
} else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) { // With owner stacks, we no longer need the type here so this comment is
typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`; // no longer true. Which is why we can run this even for invalid types.
info = const children = config.children;
' Did you accidentally export a JSX literal instead of a component?'; if (children !== undefined) {
} else { if (isStaticChildren) {
typeString = typeof type; if (isArray(children)) {
} for (let i = 0; i < children.length; i++) {
validateChildKeys(children[i], type);
}
console.error( if (Object.freeze) {
'React.jsx: type is invalid -- expected a string (for ' + Object.freeze(children);
'built-in components) or a class/function (for composite ' +
'components) but got: %s.%s',
typeString,
info,
);
} else {
// This is a valid element type.
// Skip key warning if the type isn't valid since our key validation logic
// doesn't expect a non-string/function type and can throw confusing
// errors. We don't want exception behavior to differ between dev and
// prod. (Rendering will throw with a helpful message and as soon as the
// type is fixed, the key warnings will appear.)
// When enableOwnerStacks is on, we no longer need the type here so this
// comment is no longer true. Which is why we can run this even for invalid
// types.
const children = config.children;
if (children !== undefined) {
if (isStaticChildren) {
if (isArray(children)) {
for (let i = 0; i < children.length; i++) {
validateChildKeys(children[i], type);
}
if (Object.freeze) {
Object.freeze(children);
}
} else {
console.error(
'React.jsx: Static children should always be an array. ' +
'You are likely explicitly calling React.jsxs or React.jsxDEV. ' +
'Use the Babel transform instead.',
);
} }
} else { } else {
validateChildKeys(children, type); console.error(
'React.jsx: Static children should always be an array. ' +
'You are likely explicitly calling React.jsxs or React.jsxDEV. ' +
'Use the Babel transform instead.',
);
} }
} else {
validateChildKeys(children, type);
} }
} }
@ -640,59 +587,17 @@ function jsxDEVImpl(
*/ */
export function createElement(type, config, children) { export function createElement(type, config, children) {
if (__DEV__) { if (__DEV__) {
if (!enableOwnerStacks && !isValidElementType(type)) { // We don't warn for invalid element type here because with owner stacks,
// This is just an optimistic check that provides a better stack trace before // we error in the renderer. The renderer is the only one that knows what
// owner stacks. It's really up to the renderer if it's a valid element type. // types are valid for this particular renderer so we let it error there.
// When owner stacks are enabled, we instead warn in the renderer and it'll
// have the stack trace of the JSX element anyway.
//
// This is an invalid element type.
//
// We warn in this case but don't throw. We expect the element creation to
// succeed and there will likely be errors in render.
let info = '';
if (
type === undefined ||
(typeof type === 'object' &&
type !== null &&
Object.keys(type).length === 0)
) {
info +=
' You likely forgot to export your component from the file ' +
"it's defined in, or you might have mixed up default and named imports.";
}
let typeString; // Skip key warning if the type isn't valid since our key validation logic
if (type === null) { // doesn't expect a non-string/function type and can throw confusing
typeString = 'null'; // errors. We don't want exception behavior to differ between dev and
} else if (isArray(type)) { // prod. (Rendering will throw with a helpful message and as soon as the
typeString = 'array'; // type is fixed, the key warnings will appear.)
} else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) { for (let i = 2; i < arguments.length; i++) {
typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`; validateChildKeys(arguments[i], type);
info =
' Did you accidentally export a JSX literal instead of a component?';
} else {
typeString = typeof type;
}
console.error(
'React.createElement: type is invalid -- expected a string (for ' +
'built-in components) or a class/function (for composite ' +
'components) but got: %s.%s',
typeString,
info,
);
} else {
// This is a valid element type.
// Skip key warning if the type isn't valid since our key validation logic
// doesn't expect a non-string/function type and can throw confusing
// errors. We don't want exception behavior to differ between dev and
// prod. (Rendering will throw with a helpful message and as soon as the
// type is fixed, the key warnings will appear.)
for (let i = 2; i < arguments.length; i++) {
validateChildKeys(arguments[i], type);
}
} }
// Unlike the jsx() runtime, createElement() doesn't warn about key spread. // Unlike the jsx() runtime, createElement() doesn't warn about key spread.
@ -795,8 +700,8 @@ export function createElement(type, config, children) {
undefined, undefined,
getOwner(), getOwner(),
props, props,
__DEV__ && enableOwnerStacks ? Error('react-stack-top-frame') : undefined, __DEV__ && Error('react-stack-top-frame'),
__DEV__ && enableOwnerStacks ? createTask(getTaskName(type)) : undefined, __DEV__ && createTask(getTaskName(type)),
); );
} }
@ -808,8 +713,8 @@ export function cloneAndReplaceKey(oldElement, newKey) {
undefined, undefined,
!__DEV__ ? undefined : oldElement._owner, !__DEV__ ? undefined : oldElement._owner,
oldElement.props, oldElement.props,
__DEV__ && enableOwnerStacks ? oldElement._debugStack : undefined, __DEV__ && oldElement._debugStack,
__DEV__ && enableOwnerStacks ? oldElement._debugTask : undefined, __DEV__ && oldElement._debugTask,
); );
if (__DEV__) { if (__DEV__) {
// The cloned element should inherit the original element's key validation. // The cloned element should inherit the original element's key validation.
@ -914,8 +819,8 @@ export function cloneElement(element, config, children) {
undefined, undefined,
owner, owner,
props, props,
__DEV__ && enableOwnerStacks ? element._debugStack : undefined, __DEV__ && element._debugStack,
__DEV__ && enableOwnerStacks ? element._debugTask : undefined, __DEV__ && element._debugTask,
); );
for (let i = 2; i < arguments.length; i++) { for (let i = 2; i < arguments.length; i++) {
@ -936,51 +841,13 @@ export function cloneElement(element, config, children) {
*/ */
function validateChildKeys(node, parentType) { function validateChildKeys(node, parentType) {
if (__DEV__) { if (__DEV__) {
if (enableOwnerStacks) { // With owner stacks is, no warnings happens. All we do is
// When owner stacks is enabled no warnings happens. All we do is // mark elements as being in a valid static child position so they
// mark elements as being in a valid static child position so they // don't need keys.
// don't need keys. if (isValidElement(node)) {
if (isValidElement(node)) {
if (node._store) {
node._store.validated = 1;
}
}
return;
}
if (typeof node !== 'object' || !node) {
return;
}
if (node.$$typeof === REACT_CLIENT_REFERENCE) {
// This is a reference to a client component so it's unknown.
} else if (isArray(node)) {
for (let i = 0; i < node.length; i++) {
const child = node[i];
if (isValidElement(child)) {
validateExplicitKey(child, parentType);
}
}
} else if (isValidElement(node)) {
// This element was passed in a valid location.
if (node._store) { if (node._store) {
node._store.validated = 1; node._store.validated = 1;
} }
} else {
const iteratorFn = getIteratorFn(node);
if (typeof iteratorFn === 'function') {
// Entry iterators used to provide implicit keys,
// but now we print a separate warning for them later.
if (iteratorFn !== node.entries) {
const iterator = iteratorFn.call(node);
if (iterator !== node) {
let step;
while (!(step = iterator.next()).done) {
if (isValidElement(step.value)) {
validateExplicitKey(step.value, parentType);
}
}
}
}
}
} }
} }
} }
@ -999,92 +866,3 @@ export function isValidElement(object) {
object.$$typeof === REACT_ELEMENT_TYPE object.$$typeof === REACT_ELEMENT_TYPE
); );
} }
const ownerHasKeyUseWarning = {};
/**
* Warn if the element doesn't have an explicit key assigned to it.
* This element is in an array. The array could grow and shrink or be
* reordered. All children that haven't already been validated are required to
* have a "key" property assigned to it. Error statuses are cached so a warning
* will only be shown once.
*
* @internal
* @param {ReactElement} element Element that requires a key.
* @param {*} parentType element's parent's type.
*/
function validateExplicitKey(element, parentType) {
if (enableOwnerStacks) {
// Skip. Will verify in renderer instead.
return;
}
if (__DEV__) {
if (!element._store || element._store.validated || element.key != null) {
return;
}
element._store.validated = 1;
const currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {
return;
}
ownerHasKeyUseWarning[currentComponentErrorInfo] = true;
// Usually the current owner is the offender, but if it accepts children as a
// property, it may be the creator of the child that's responsible for
// assigning it a key.
let childOwner = '';
if (element && element._owner != null && element._owner !== getOwner()) {
let ownerName = null;
if (typeof element._owner.tag === 'number') {
ownerName = getComponentNameFromType(element._owner.type);
} else if (typeof element._owner.name === 'string') {
ownerName = element._owner.name;
}
// Give the component that originally created this child.
childOwner = ` It was passed a child from ${ownerName}.`;
}
const prevGetCurrentStack = ReactSharedInternals.getCurrentStack;
ReactSharedInternals.getCurrentStack = function () {
const owner = element._owner;
// Add an extra top frame while an element is being validated
let stack = describeUnknownElementTypeFrameInDEV(
element.type,
owner ? owner.type : null,
);
// Delegate to the injected renderer-specific implementation
if (prevGetCurrentStack) {
stack += prevGetCurrentStack() || '';
}
return stack;
};
console.error(
'Each child in a list should have a unique "key" prop.' +
'%s%s See https://react.dev/link/warning-keys for more information.',
currentComponentErrorInfo,
childOwner,
);
ReactSharedInternals.getCurrentStack = prevGetCurrentStack;
}
}
function getCurrentComponentErrorInfo(parentType) {
if (__DEV__) {
let info = '';
const owner = getOwner();
if (owner) {
const name = getComponentNameFromType(owner.type);
if (name) {
info = '\n\nCheck the render method of `' + name + '`.';
}
}
if (!info) {
const parentName = getComponentNameFromType(parentType);
if (parentName) {
info = `\n\nCheck the top-level render call using <${parentName}>.`;
}
}
return info;
}
}

View File

@ -11,14 +11,12 @@ import type {ReactComponentInfo} from 'shared/ReactTypes';
import {describeBuiltInComponentFrame} from 'shared/ReactComponentStackFrame'; import {describeBuiltInComponentFrame} from 'shared/ReactComponentStackFrame';
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import {formatOwnerStack} from 'shared/ReactOwnerStackFrames'; import {formatOwnerStack} from 'shared/ReactOwnerStackFrames';
export function getOwnerStackByComponentInfoInDev( export function getOwnerStackByComponentInfoInDev(
componentInfo: ReactComponentInfo, componentInfo: ReactComponentInfo,
): string { ): string {
if (!enableOwnerStacks || !__DEV__) { if (!__DEV__) {
return ''; return '';
} }
try { try {

View File

@ -7,25 +7,12 @@
* @flow * @flow
*/ */
import type {LazyComponent} from 'react/src/ReactLazy';
import {
REACT_SUSPENSE_TYPE,
REACT_SUSPENSE_LIST_TYPE,
REACT_FORWARD_REF_TYPE,
REACT_MEMO_TYPE,
REACT_LAZY_TYPE,
REACT_VIEW_TRANSITION_TYPE,
} from 'shared/ReactSymbols';
import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev'; import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev';
import ReactSharedInternals from 'shared/ReactSharedInternals'; import ReactSharedInternals from 'shared/ReactSharedInternals';
import DefaultPrepareStackTrace from 'shared/DefaultPrepareStackTrace'; import DefaultPrepareStackTrace from 'shared/DefaultPrepareStackTrace';
import {enableViewTransition} from 'shared/ReactFeatureFlags';
let prefix; let prefix;
let suffix; let suffix;
export function describeBuiltInComponentFrame(name: string): string { export function describeBuiltInComponentFrame(name: string): string {
@ -300,53 +287,3 @@ export function describeClassComponentFrame(ctor: Function): string {
export function describeFunctionComponentFrame(fn: Function): string { export function describeFunctionComponentFrame(fn: Function): string {
return describeNativeComponentFrame(fn, false); return describeNativeComponentFrame(fn, false);
} }
function shouldConstruct(Component: Function) {
const prototype = Component.prototype;
return !!(prototype && prototype.isReactComponent);
}
// TODO: Delete this once the key warning no longer uses it. I.e. when enableOwnerStacks ship.
export function describeUnknownElementTypeFrameInDEV(type: any): string {
if (!__DEV__) {
return '';
}
if (type == null) {
return '';
}
if (typeof type === 'function') {
return describeNativeComponentFrame(type, shouldConstruct(type));
}
if (typeof type === 'string') {
return describeBuiltInComponentFrame(type);
}
switch (type) {
case REACT_SUSPENSE_TYPE:
return describeBuiltInComponentFrame('Suspense');
case REACT_SUSPENSE_LIST_TYPE:
return describeBuiltInComponentFrame('SuspenseList');
case REACT_VIEW_TRANSITION_TYPE:
if (enableViewTransition) {
return describeBuiltInComponentFrame('ViewTransition');
}
}
if (typeof type === 'object') {
switch (type.$$typeof) {
case REACT_FORWARD_REF_TYPE:
return describeFunctionComponentFrame(type.render);
case REACT_MEMO_TYPE:
// Memo may contain any component type so we recursively resolve it.
return describeUnknownElementTypeFrameInDEV(type.type);
case REACT_LAZY_TYPE: {
const lazyComponent: LazyComponent<any, any> = (type: any);
const payload = lazyComponent._payload;
const init = lazyComponent._init;
try {
// Lazy may contain any component type so we recursively resolve it.
return describeUnknownElementTypeFrameInDEV(init(payload));
} catch (x) {}
}
}
}
return '';
}

View File

@ -136,8 +136,6 @@ export const passChildrenWhenCloningPersistedNodes = false;
*/ */
export const enablePersistedModeClonedFlag = false; export const enablePersistedModeClonedFlag = false;
export const enableOwnerStacks = true;
export const enableShallowPropDiffing = false; export const enableShallowPropDiffing = false;
export const enableSiblingPrerendering = true; export const enableSiblingPrerendering = true;

View File

@ -32,9 +32,6 @@ export const {
enableLazyPublicInstanceInFabric, enableLazyPublicInstanceInFabric,
} = dynamicFlags; } = dynamicFlags;
// These two can be removed
export const enableOwnerStacks = true;
// The rest of the flags are static for better dead code elimination. // The rest of the flags are static for better dead code elimination.
export const disableClientCache = true; export const disableClientCache = true;
export const disableCommentsAsDOMContainers = true; export const disableCommentsAsDOMContainers = true;

View File

@ -41,7 +41,6 @@ export const enableLegacyFBSupport = false;
export const enableLegacyHidden = false; export const enableLegacyHidden = false;
export const enableNoCloningMemoCache = false; export const enableNoCloningMemoCache = false;
export const enableObjectFiber = false; export const enableObjectFiber = false;
export const enableOwnerStacks = true;
export const enablePersistedModeClonedFlag = false; export const enablePersistedModeClonedFlag = false;
export const enablePostpone = false; export const enablePostpone = false;
export const enableReactTestRendererWarning = false; export const enableReactTestRendererWarning = false;

View File

@ -91,7 +91,6 @@ export const enableReactTestRendererWarning = true;
export const disableDefaultPropsExceptForClasses = true; export const disableDefaultPropsExceptForClasses = true;
export const enableObjectFiber = false; export const enableObjectFiber = false;
export const enableOwnerStacks = true;
// Flow magic to verify the exports of this file match the original version. // Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType); ((((null: any): ExportsType): FeatureFlagsType): ExportsType);

View File

@ -35,7 +35,6 @@ export const enableLegacyFBSupport = false;
export const enableLegacyHidden = false; export const enableLegacyHidden = false;
export const enableNoCloningMemoCache = false; export const enableNoCloningMemoCache = false;
export const enableObjectFiber = false; export const enableObjectFiber = false;
export const enableOwnerStacks = true;
export const enablePersistedModeClonedFlag = false; export const enablePersistedModeClonedFlag = false;
export const enablePostpone = false; export const enablePostpone = false;
export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerCommitHooks = __PROFILE__;

View File

@ -71,7 +71,6 @@ export const disableDefaultPropsExceptForClasses = true;
export const renameElementSymbol = false; export const renameElementSymbol = false;
export const enableObjectFiber = false; export const enableObjectFiber = false;
export const enableOwnerStacks = true;
export const enableShallowPropDiffing = false; export const enableShallowPropDiffing = false;
export const enableSiblingPrerendering = true; export const enableSiblingPrerendering = true;

View File

@ -43,9 +43,6 @@ export const {
// On WWW, __EXPERIMENTAL__ is used for a new modern build. // On WWW, __EXPERIMENTAL__ is used for a new modern build.
// It's not used anywhere in production yet. // It's not used anywhere in production yet.
// Can remove these two
export const enableOwnerStacks = true;
export const enableProfilerTimer = __PROFILE__; export const enableProfilerTimer = __PROFILE__;
export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerCommitHooks = __PROFILE__;
export const enableProfilerNestedUpdatePhase = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__;

View File

@ -36,7 +36,7 @@ import {
const REACT_CLIENT_REFERENCE: symbol = Symbol.for('react.client.reference'); const REACT_CLIENT_REFERENCE: symbol = Symbol.for('react.client.reference');
// This function is deprecated. Don't use. Only the renderer knows what a valid type is. // This function is deprecated. Don't use. Only the renderer knows what a valid type is.
// TODO: Delete this when enableOwnerStacks ships. // TODO: Delete this now that owner stacks shipped.
export default function isValidElementType(type: mixed): boolean { export default function isValidElementType(type: mixed): boolean {
if (typeof type === 'string' || typeof type === 'function') { if (typeof type === 'string' || typeof type === 'function') {
return true; return true;

View File

@ -11,7 +11,6 @@ jest.mock('shared/ReactFeatureFlags', () => {
// Flags that aren't currently used, but we still want to force variants to keep the // Flags that aren't currently used, but we still want to force variants to keep the
// code live. // code live.
actual.disableInputAttributeSyncing = __VARIANT__; actual.disableInputAttributeSyncing = __VARIANT__;
actual.enableOwnerStacks = __VARIANT__;
// These are hardcoded to true for the next release, // These are hardcoded to true for the next release,
// but still run the tests against both variants until // but still run the tests against both variants until

View File

@ -11,8 +11,6 @@ jest.mock('shared/ReactFeatureFlags', () => {
'shared/forks/ReactFeatureFlags.native-fb.js' 'shared/forks/ReactFeatureFlags.native-fb.js'
); );
actual.enableOwnerStacks = __VARIANT__;
// Lots of tests use these, but we don't want to expose it to RN. // Lots of tests use these, but we don't want to expose it to RN.
// Ideally, tests for xplat wouldn't use react-dom, but many of our tests do. // Ideally, tests for xplat wouldn't use react-dom, but many of our tests do.
// Since the xplat tests run with the www entry points, some of these flags // Since the xplat tests run with the www entry points, some of these flags