[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."
`);
} 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 {
expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected)
@ -937,20 +926,6 @@ describe('ReactInternalTestUtils console assertions', () => {
+ B
+ 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."
`);
} else {
@ -959,16 +934,10 @@ describe('ReactInternalTestUtils console assertions', () => {
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 **)
You must call one of the assertConsoleDev helpers between each act call."
@ -1023,33 +992,6 @@ describe('ReactInternalTestUtils console assertions', () => {
+ B
+ 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."
`);
} else {
@ -1063,30 +1005,18 @@ describe('ReactInternalTestUtils console assertions', () => {
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."
@ -1927,20 +1857,6 @@ describe('ReactInternalTestUtils console assertions', () => {
+ 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."
`);
} else {
@ -1950,13 +1866,10 @@ describe('ReactInternalTestUtils console assertions', () => {
console.warn was called without assertConsoleWarnDev:
+ Not asserted%s,
+ in Yield (at **)
+ in div (at **)
+ Not asserted%s,
+ in Yield (at **)
+ in div (at **)
+ Not asserted%s,
+ in Yield (at **)
+ in div (at **)
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."
`);
} else if (gate(flags => flags.enableOwnerStacks)) {
} else {
expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected)
@ -2034,26 +1947,6 @@ describe('ReactInternalTestUtils console assertions', () => {
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."
`);
} else if (gate(flags => flags.enableOwnerStacks)) {
} else {
expect(message).toMatchInlineSnapshot(`
"asserConsoleLogsCleared(expected)
@ -2133,45 +2026,6 @@ describe('ReactInternalTestUtils console assertions', () => {
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
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."
`);
} else {
@ -3075,13 +2915,10 @@ describe('ReactInternalTestUtils console assertions', () => {
console.error was called without assertConsoleErrorDev:
+ Not asserted%s,
+ in Yield (at **)
+ in div (at **)
+ Not asserted%s,
+ in Yield (at **)
+ in div (at **)
+ Not asserted%s,
+ in Yield (at **)
+ in div (at **)
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 */
const chalk = require('chalk');
const util = require('util');
const shouldIgnoreConsoleError = require('./shouldIgnoreConsoleError');
@ -38,25 +39,16 @@ const patchConsoleMethod = (methodName, logged) => {
(methodName === 'error' || methodName === 'warn')
) {
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) {
// enableOwnerStacks enabled. When it's always on, we can assume this case.
const stack = React.captureOwnerStack();
if (stack) {
format += '%s';
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" +
'To use non-primitive values as keys, you must pass a hash ' +
'function as the second argument to createResource().\n' +
' in App (at **)' +
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in Suspense (at **)'),
' in App (at **)',
...(gate('enableSiblingPrerendering')
? [
'Invalid key type. Expected a string, number, symbol, or ' +

View File

@ -45,7 +45,6 @@ import type {TemporaryReferenceSet} from './ReactFlightTemporaryReferences';
import {
enablePostpone,
enableOwnerStacks,
enableProfilerTimer,
enableComponentPerformanceTrack,
} from 'shared/ReactFeatureFlags';
@ -755,7 +754,7 @@ function createElement(
configurable: false,
enumerable: false,
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.
Object.defineProperty(element, '_debugInfo', {
@ -765,79 +764,68 @@ function createElement(
value: null,
});
let env = response._rootEnvironmentName;
if (enableOwnerStacks) {
if (owner !== null && owner.env != null) {
// 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
// it must be the same environment as the owner. We could send it separately
// but it seems a bit unnecessary for this edge case.
env = owner.env;
}
let normalizedStackTrace: null | Error = null;
if (owner === null && response._debugRootStack != null) {
// 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.
normalizedStackTrace = response._debugRootStack;
} else if (stack !== null) {
// 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
// of the browser and the stack frames will have been registered with
// source mapping information.
// This can unfortunately happen within a user space callstack which will
// remain on the stack.
normalizedStackTrace = createFakeJSXCallStackInDEV(
response,
stack,
env,
);
}
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,
});
if (owner !== null && owner.env != null) {
// 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
// it must be the same environment as the owner. We could send it separately
// but it seems a bit unnecessary for this edge case.
env = owner.env;
}
let normalizedStackTrace: null | Error = null;
if (owner === null && response._debugRootStack != null) {
// 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.
normalizedStackTrace = response._debugRootStack;
} else if (stack !== null) {
// 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
// of the browser and the stack frames will have been registered with
// source mapping information.
// This can unfortunately happen within a user space callstack which will
// remain on the stack.
normalizedStackTrace = createFakeJSXCallStackInDEV(response, stack, env);
}
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.
if (owner !== null) {
initializeFakeStack(response, owner);
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,
});
// 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) {
@ -863,13 +851,11 @@ function createElement(
name: getComponentNameFromType(element.type) || '',
owner: element._owner,
};
if (enableOwnerStacks) {
// $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write]
erroredComponent.debugTask = element._debugTask;
}
erroredComponent.debugTask = element._debugTask;
}
erroredChunk._debugInfo = [erroredComponent];
}
@ -1057,13 +1043,11 @@ function waitForReference<T>(
name: getComponentNameFromType(element.type) || '',
owner: element._owner,
};
if (enableOwnerStacks) {
// $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write]
erroredComponent.debugTask = element._debugTask;
}
erroredComponent.debugTask = element._debugTask;
}
const chunkDebugInfo: ReactDebugInfo =
chunk._debugInfo || (chunk._debugInfo = []);
@ -1223,13 +1207,11 @@ function loadServerReference<A: Iterable<any>, T>(
name: getComponentNameFromType(element.type) || '',
owner: element._owner,
};
if (enableOwnerStacks) {
// $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write]
erroredComponent.debugStack = element._debugStack;
if (supportsCreateTask) {
// $FlowFixMe[cannot-write]
erroredComponent.debugTask = element._debugTask;
}
erroredComponent.debugTask = element._debugTask;
}
const chunkDebugInfo: ReactDebugInfo =
chunk._debugInfo || (chunk._debugInfo = []);
@ -1609,8 +1591,8 @@ function parseModelTuple(
tuple[2],
tuple[3],
__DEV__ ? (tuple: any)[4] : null,
__DEV__ && enableOwnerStacks ? (tuple: any)[5] : null,
__DEV__ && enableOwnerStacks ? (tuple: any)[6] : 0,
__DEV__ ? (tuple: any)[5] : null,
__DEV__ ? (tuple: any)[6] : 0,
);
}
return value;
@ -2083,27 +2065,6 @@ function stopStream(
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};
function resolveErrorProd(response: Response): Error {
if (__DEV__) {
@ -2202,34 +2163,20 @@ function resolvePostponeDev(
);
}
let postponeInstance: Postpone;
if (!enableOwnerStacks) {
// Executing Error within a native stack isn't really limited to owner stacks
// but we gate it behind the same flag for now while iterating.
// eslint-disable-next-line react-internal/prod-error-codes
postponeInstance = (Error(reason || ''): any);
postponeInstance.$$typeof = REACT_POSTPONE_TYPE;
// For backwards compat we use the V8 formatting when the flag is off.
postponeInstance.stack = formatV8Stack(
postponeInstance.name,
postponeInstance.message,
stack,
);
const callStack = buildFakeCallStack(
response,
stack,
env,
// $FlowFixMe[incompatible-use]
Error.bind(null, reason || ''),
);
const rootTask = response._debugRootTask;
if (rootTask != null) {
postponeInstance = rootTask.run(callStack);
} else {
const callStack = buildFakeCallStack(
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 = callStack();
}
postponeInstance.$$typeof = REACT_POSTPONE_TYPE;
const chunks = response._chunks;
const chunk = chunks.get(id);
if (!chunk) {
@ -2248,8 +2195,7 @@ function resolveHint<Code: HintCode>(
dispatchHint(code, hintModel);
}
const supportsCreateTask =
__DEV__ && enableOwnerStacks && !!(console: any).createTask;
const supportsCreateTask = __DEV__ && !!(console: any).createTask;
type FakeFunction<T> = (() => T) => T;
const fakeFunctionCache: Map<string, FakeFunction<any>> = __DEV__
@ -2590,15 +2536,11 @@ function resolveDebugInfo(
let currentOwnerInDEV: null | ReactComponentInfo = null;
function getCurrentStackInDEV(): string {
if (__DEV__) {
if (enableOwnerStacks) {
const owner: null | ReactComponentInfo = currentOwnerInDEV;
if (owner === null) {
return '';
}
return getOwnerStackByComponentInfoInDev(owner);
const owner: null | ReactComponentInfo = currentOwnerInDEV;
if (owner === null) {
return '';
}
// We don't have Parent Stacks in Flight.
return '';
return getOwnerStackByComponentInfoInDev(owner);
}
return '';
}

View File

@ -321,9 +321,7 @@ describe('ReactFlight', () => {
env: 'Server',
key: null,
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Object.<anonymous> (at **)'
: undefined,
stack: ' in Object.<anonymous> (at **)',
props: {
firstName: 'Seb',
lastName: 'Smith',
@ -367,9 +365,7 @@ describe('ReactFlight', () => {
env: 'Server',
key: null,
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Object.<anonymous> (at **)'
: undefined,
stack: ' in Object.<anonymous> (at **)',
props: {
firstName: 'Seb',
lastName: 'Smith',
@ -1400,30 +1396,19 @@ describe('ReactFlight', () => {
environmentName: 'Server',
},
],
findSourceMapURLCalls: gate(flags => flags.enableOwnerStacks)
? [
[__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'],
[__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'],
],
findSourceMapURLCalls: [
[__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'],
[__filename, 'Server'],
],
});
} else {
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' +
' in span (at **)\n' +
' in Component (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Indirection (at **)\n') +
' in App (at **)',
]);
});
@ -1538,46 +1520,26 @@ describe('ReactFlight', () => {
},
};
const transport = ReactNoopFlightServer.render(<input value={obj} />);
if (gate(flags => flags.enableOwnerStacks)) {
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([
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' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
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' +
' ^^^^^^^^^^^^^^^',
'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},
);
}
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
ReactNoopFlightClient.read(transport);
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' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
});
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(
<div>Womp womp: {new MyError('spaghetti')}</div>,
);
if (gate(flags => flags.enableOwnerStacks)) {
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([
assertConsoleErrorDev(
[
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'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' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
],
{withoutStack: true},
);
}
' ^^^^^^^',
],
{withoutStack: true},
);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^\n' +
' at (<anonymous>)',
]);
});
it('should warn in DEV if a special object is passed to a host component', () => {
const transport = ReactNoopFlightServer.render(<input value={Math} />);
if (gate(flags => flags.enableOwnerStacks)) {
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([
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
' ^^^^^^',
],
{withoutStack: true},
);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^\n' +
' at (<anonymous>)',
]);
});
it('should warn in DEV if an object with symbols is passed to a host component', () => {
const transport = ReactNoopFlightServer.render(
<input value={{[Symbol.iterator]: {}}} />,
);
if (gate(flags => flags.enableOwnerStacks)) {
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([
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' +
' ^^^^\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' +
' <input 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' +
' <input value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
' ^^^^',
],
{withoutStack: true},
);
ReactNoopFlightClient.read(transport);
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' +
' ^^^^\n' +
' at (<anonymous>)',
]);
});
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 transport = ReactNoopFlightServer.render(<Client value={obj} />);
if (gate(flags => flags.enableOwnerStacks)) {
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([
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' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
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' +
' ^^^^^^^^^^^^^^^',
'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},
);
}
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
ReactNoopFlightClient.read(transport);
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' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
});
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(
<Client>Current date: {obj}</Client>,
);
if (gate(flags => flags.enableOwnerStacks)) {
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([
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' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
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' +
' ^^^^^^^^^^^^^^^',
'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},
);
}
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
ReactNoopFlightClient.read(transport);
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' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
});
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 transport = ReactNoopFlightServer.render(<Client value={Math} />);
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([
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
' ^^^^^^',
],
{withoutStack: true},
);
ReactNoopFlightClient.read(transport);
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^\n' +
' at (<anonymous>)',
]);
});
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(
<Client value={{[Symbol.iterator]: {}}} />,
);
if (gate(flags => flags.enableOwnerStacks)) {
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([
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' +
' ^^^^\n',
]);
} 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},
);
ReactNoopFlightClient.read(transport);
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' +
' ^^^^\n',
]);
});
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);
if (gate(flags => flags.enableOwnerStacks)) {
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},
],
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' +
' ^^^^\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},
);
}
],
'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', () => {
@ -1956,36 +1773,20 @@ describe('ReactFlight', () => {
<Client value={['looooong string takes up noise', Math, <h1>hi</h1>]} />,
);
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
{withoutStack: true},
],
assertConsoleErrorDev([
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\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},
);
}
],
'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', () => {
@ -2012,26 +1813,16 @@ describe('ReactFlight', () => {
jest.resetModules();
jest.mock('react', () => React);
ReactNoopFlightClient.read(transport);
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 NoKey (at **)',
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' 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 **)',
]);
}
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in NoKey (at **)',
'Each child in a list should have a unique "key" prop. ' +
'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', () => {
// While we're on the server we need to have the Server version active to track component stacks.
jest.resetModules();
@ -2046,23 +1837,14 @@ describe('ReactFlight', () => {
jest.resetModules();
jest.mock('react', () => React);
ReactNoopFlightClient.read(transport);
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 Fragment (at **)',
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' 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 **)',
]);
}
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Fragment (at **)',
'Each child in a list should have a unique "key" prop. ' +
'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 () => {
@ -2079,20 +1861,12 @@ describe('ReactFlight', () => {
ReactNoop.render(await ReactNoopFlightClient.read(transport));
});
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ParentClient>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' 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 **)',
]);
}
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ParentClient>. ' +
'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', () => {
@ -3039,9 +2813,7 @@ describe('ReactFlight', () => {
env: 'Server',
key: null,
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Object.<anonymous> (at **)'
: undefined,
stack: ' in Object.<anonymous> (at **)',
props: {
transport: expect.arrayContaining([]),
},
@ -3063,9 +2835,7 @@ describe('ReactFlight', () => {
env: 'third-party',
key: null,
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Object.<anonymous> (at **)'
: undefined,
stack: ' in Object.<anonymous> (at **)',
props: {},
},
{time: 14},
@ -3082,9 +2852,7 @@ describe('ReactFlight', () => {
env: 'third-party',
key: null,
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in myLazy (at **)\n in lazyInitializer (at **)'
: undefined,
stack: ' in myLazy (at **)\n in lazyInitializer (at **)',
props: {},
},
{time: 16},
@ -3100,9 +2868,7 @@ describe('ReactFlight', () => {
env: 'third-party',
key: '3',
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Object.<anonymous> (at **)'
: undefined,
stack: ' in Object.<anonymous> (at **)',
props: {},
},
{time: 12},
@ -3176,9 +2942,7 @@ describe('ReactFlight', () => {
env: 'Server',
key: null,
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Object.<anonymous> (at **)'
: undefined,
stack: ' in Object.<anonymous> (at **)',
props: {
transport: expect.arrayContaining([]),
},
@ -3198,9 +2962,7 @@ describe('ReactFlight', () => {
env: 'Server',
key: 'keyed',
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in ServerComponent (at **)'
: undefined,
stack: ' in ServerComponent (at **)',
props: {
children: {},
},
@ -3219,9 +2981,7 @@ describe('ReactFlight', () => {
env: 'third-party',
key: null,
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Object.<anonymous> (at **)'
: undefined,
stack: ' in Object.<anonymous> (at **)',
props: {},
},
{time: 12},
@ -3335,19 +3095,13 @@ describe('ReactFlight', () => {
});
expect(sawReactPrefix).toBe(false);
if (__DEV__ && gate(flags => flags.enableOwnerStacks)) {
if (__DEV__) {
expect(environments.slice(0, 4)).toEqual([
'Server',
'third-party',
'third-party',
'third-party',
]);
} else if (__DEV__) {
expect(environments.slice(0, 3)).toEqual([
'third-party',
'third-party',
'third-party',
]);
} else {
expect(environments).toEqual([]);
}
@ -3384,9 +3138,7 @@ describe('ReactFlight', () => {
env: 'A',
key: null,
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Object.<anonymous> (at **)'
: undefined,
stack: ' in Object.<anonymous> (at **)',
props: {},
},
{
@ -3402,7 +3154,7 @@ describe('ReactFlight', () => {
expect(ReactNoop).toMatchRenderedOutput(<div>hi</div>);
});
// @gate __DEV__ && enableOwnerStacks
// @gate __DEV__
it('replays logs, but not onError logs', async () => {
function foo() {
return 'hello';
@ -3574,9 +3326,7 @@ describe('ReactFlight', () => {
env: 'Server',
key: null,
owner: null,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Object.<anonymous> (at **)'
: undefined,
stack: ' in Object.<anonymous> (at **)',
props: {
firstName: 'Seb',
},
@ -3590,9 +3340,7 @@ describe('ReactFlight', () => {
env: 'Server',
key: null,
owner: greetInfo,
stack: gate(flag => flag.enableOwnerStacks)
? ' in Greeting (at **)'
: undefined,
stack: ' in Greeting (at **)',
props: {
children: expect.objectContaining({
type: 'span',
@ -3617,7 +3365,7 @@ describe('ReactFlight', () => {
expect(ReactNoop).toMatchRenderedOutput(<span>Hello, Seb</span>);
});
// @gate __DEV__ && enableOwnerStacks
// @gate __DEV__
it('can get the component owner stacks during rendering in dev', () => {
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 () => {
jest.resetModules();
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 () => {
const thrownError = new Error('hi');
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)', () => {
class MyError extends Error {
toJSON() {

View File

@ -2347,10 +2347,7 @@ describe('ReactHooksInspectionIntegration', () => {
await act(async () => await LazyFoo);
assertConsoleErrorDev([
'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 **)'),
'Foo: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
]);
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.
// 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 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.
// Postprocess Profile data

View File

@ -10,8 +10,6 @@
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import type {HydrationDiffNode} from 'react-reconciler/src/ReactFiberHydrationDiffs';
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import {
current,
runWithFiberInDEV,
@ -615,7 +613,7 @@ function validateDOMNesting(
ancestorDescription,
);
}
if (enableOwnerStacks && child) {
if (child) {
// For debugging purposes find the nearest ancestor that caused the issue.
// 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.

View File

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

View File

@ -75,8 +75,7 @@ describe('ReactChildReconciler', () => {
'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' +
' <h1>{fn}</h1>\n' +
' in h1 (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in div (at **)'),
' in h1 (at **)',
]);
const node = container.firstChild;
@ -100,7 +99,6 @@ describe('ReactChildReconciler', () => {
'Keys should be unique so that components maintain their identity across updates. ' +
'Non-unique keys may cause children to be duplicated and/or omitted — ' +
'the behavior is unsupported and could change in a future version.\n' +
(gate('enableOwnerStacks') ? '' : ' in div (at **)\n') +
' in div (at **)\n' +
' in Component (at **)',
]);
@ -137,11 +135,7 @@ describe('ReactChildReconciler', () => {
'duplicated and/or omitted — the behavior is unsupported and ' +
'could change in a future version.\n' +
' in div (at **)\n' +
(gate(flags => flags.enableOwnerStacks) ? '' : ' in div (at **)\n') +
' in Component (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Parent (at **)\n') +
' in GrandParent (at **)',
]);
});
@ -165,7 +159,6 @@ describe('ReactChildReconciler', () => {
'duplicated and/or omitted — the behavior is unsupported and ' +
'could change in a future version.\n' +
' in div (at **)\n' +
(gate(flags => flags.enableOwnerStacks) ? '' : ' in div (at **)\n') +
' in Component (at **)',
]);
});
@ -201,11 +194,7 @@ describe('ReactChildReconciler', () => {
'duplicated and/or omitted — the behavior is unsupported and ' +
'could change in a future version.\n' +
' in div (at **)\n' +
(gate(flags => flags.enableOwnerStacks) ? '' : ' in div (at **)\n') +
' in Component (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Parent (at **)\n') +
' in GrandParent (at **)',
]);
});

View File

@ -407,17 +407,6 @@ describe('ReactComponent', () => {
const X = undefined;
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 act(() => {
root.render(XElement);
@ -433,15 +422,6 @@ describe('ReactComponent', () => {
const Y = null;
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 act(() => {
root.render(YElement);
@ -453,15 +433,6 @@ describe('ReactComponent', () => {
const Z = true;
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 act(() => {
root.render(ZElement);
@ -506,26 +477,6 @@ describe('ReactComponent', () => {
'\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 () => {
@ -693,9 +644,6 @@ describe('ReactComponent', () => {
'Or maybe you meant to call this function rather than return it.\n' +
' <span>{Foo}</span>\n' +
' in span (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in div (at **)\n') +
' in Foo (at **)',
]);
});
@ -753,9 +701,6 @@ describe('ReactComponent', () => {
'Or maybe you meant to call this function rather than return it.\n' +
' <span>{Foo}</span>\n' +
' in span (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in div (at **)\n') +
' in Foo (at **)',
]);
await act(() => {

View File

@ -1396,9 +1396,6 @@ describe('ReactCompositeComponent', () => {
'Cannot update a component (`A`) while rendering a different component (`B`). ' +
'To locate the bad setState() call inside `B`, ' +
'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 **)',
]);

View File

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

View File

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

View File

@ -751,7 +751,6 @@ describe('ReactDOMFiber', () => {
' in Parent (at **)',
'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' +
(gate('enableOwnerStacks') ? '' : ' in Component (at **)\n') +
' in Parent (at **)',
]);
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. ' +
'The function will always be executed in the same window.\n' +
' in input (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in form (at **)\n') +
' in App (at **)',
]);
let root;

View File

@ -1843,15 +1843,9 @@ describe('ReactDOMFizzServer', () => {
assertConsoleErrorDev([
'<inCorrectTag /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.' +
'\n' +
(gate(flags => flags.enableOwnerStacks)
? ' in inCorrectTag (at **)\n' +
' in C (at **)\n' +
' in A (at **)'
: ' in inCorrectTag (at **)\n' +
' in C (at **)\n' +
' in Suspense (at **)\n' +
' in div (at **)\n' +
' in A (at **)'),
' in inCorrectTag (at **)\n' +
' in C (at **)\n' +
' in A (at **)',
]);
await act(() => {
@ -1862,17 +1856,11 @@ describe('ReactDOMFizzServer', () => {
assertConsoleErrorDev([
'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' +
(gate(flags => flags.enableOwnerStacks)
? ' in span (at **)\n' +
' in mapper (at **)\n' +
' in Array.map (at **)\n' +
' in B (at **)\n' +
' in A (at **)'
: ' in span (at **)\n' +
' in B (at **)\n' +
' in Suspense (at **)\n' +
' in div (at **)\n' +
' in A (at **)'),
' in span (at **)\n' +
' in mapper (at **)\n' +
' in Array.map (at **)\n' +
' in B (at **)\n' +
' in A (at **)',
]);
expect(getVisibleChildren(container)).toEqual(
@ -1954,13 +1942,7 @@ describe('ReactDOMFizzServer', () => {
' in TestProvider (at **)',
'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' +
' in TestConsumer (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n in TestProvider (at **)' +
'\n in Suspense (at **)' +
'\n in div (at **)' +
'\n in TestProvider (at **)'),
' in TestConsumer (at **)',
]);
expect(getVisibleChildren(container)).toEqual(
<div>
@ -5871,7 +5853,6 @@ describe('ReactDOMFizzServer', () => {
'If your `children` prop is using this form try rewriting it using a template string: ' +
'<title>{`hello ${nameOfUser}`}</title>.\n' +
' in title (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in head (at **)\n') +
' in App (at **)',
]);
@ -5917,7 +5898,6 @@ describe('ReactDOMFizzServer', () => {
'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' +
' in title (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in head (at **)\n') +
' in App (at **)',
]);
// 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 ' +
'use to produce a valid <title>.\n' +
' in title (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in head (at **)\n') +
' in App (at **)',
]);
// object titles are toStringed when float is on
@ -6545,23 +6524,11 @@ describe('ReactDOMFizzServer', () => {
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.' +
componentStack(
gate(flags => flags.enableOwnerStacks)
? ['script', 'App']
: ['script', 'body', 'html', 'App'],
),
componentStack(['script', '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.' +
componentStack(
gate(flags => flags.enableOwnerStacks)
? ['script', 'App']
: ['script', 'body', 'html', 'App'],
),
componentStack(['script', '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.' +
componentStack(
gate(flags => flags.enableOwnerStacks)
? ['script', 'App']
: ['script', 'body', 'html', 'App'],
),
componentStack(['script', 'App']),
]);
});
@ -8544,7 +8511,7 @@ describe('ReactDOMFizzServer', () => {
expect(document.body.textContent).toBe('HelloWorld');
});
// @gate __DEV__ && enableOwnerStacks
// @gate __DEV__
it('can get the component owner stacks during rendering in dev', async () => {
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 () => {
const thrownError = new Error('hi');
let caughtError;
@ -9111,56 +9078,30 @@ describe('ReactDOMFizzServer', () => {
</body>
</html>,
);
if (gate(flags => flags.enableOwnerStacks)) {
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.',
{withoutStack: true},
],
'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 App (at **)',
'<html> cannot contain a nested <meta>.\nSee this log for the ancestor stack trace.' +
'\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.',
{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 **)',
]);
}
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.',
{withoutStack: true},
],
'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 App (at **)',
'<html> cannot contain a nested <meta>.\nSee this log for the ancestor stack trace.' +
'\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.',
{withoutStack: true},
],
]);
await root.unmount();
expect(getVisibleChildren(document)).toEqual(
@ -9253,56 +9194,30 @@ describe('ReactDOMFizzServer', () => {
</body>
</html>,
);
if (gate(flags => flags.enableOwnerStacks)) {
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.',
{withoutStack: true},
],
'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 App (at **)',
'<html> cannot contain a nested <meta>.\nSee this log for the ancestor stack trace.' +
'\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.',
{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 **)',
]);
}
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.',
{withoutStack: true},
],
'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 App (at **)',
'<html> cannot contain a nested <meta>.\nSee this log for the ancestor stack trace.' +
'\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.',
{withoutStack: true},
],
]);
await root.unmount();
expect(getVisibleChildren(document)).toEqual(

View File

@ -529,8 +529,7 @@ describe('ReactDOMFloat', () => {
'> <template>\n' +
' ...\n' +
'\n' +
' in template (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
' in template (at **)',
]);
root.render(
@ -555,8 +554,7 @@ describe('ReactDOMFloat', () => {
' <body>\n' +
'> <style>\n' +
'\n' +
' in style (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
' in style (at **)',
]);
root.render(
@ -596,8 +594,7 @@ describe('ReactDOMFloat', () => {
' <body>\n' +
'> <script href="foo">\n' +
'\n' +
' in script (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
' in script (at **)',
]);
root.render(
@ -2269,21 +2266,11 @@ body {
'spell it as lowercase `nonstandardattr` instead. If you accidentally passed it from a ' +
'parent component, remove it from the DOM element.\n' +
' in link (at **)\n' +
(gate('enableOwnerStacks')
? ''
: ' in div (at **)\n' +
' in body (at **)\n' +
' in html (at **)\n') +
' in App (at **)',
'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. ' +
'For details, see https://react.dev/link/attribute-behavior \n' +
' in link (at **)\n' +
(gate('enableOwnerStacks')
? ''
: ' in div (at **)\n' +
' in body (at **)\n' +
' in html (at **)\n') +
' in App (at **)',
]);
@ -2642,8 +2629,7 @@ body {
'> <html>\n' +
'> <meta itemProp="foo">' +
'\n' +
'\n in meta (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
'\n in meta (at **)',
]);
});
@ -2668,8 +2654,7 @@ body {
'> <html>\n' +
'> <title itemProp="foo">' +
'\n' +
'\n in title (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
'\n in title (at **)',
]);
});
@ -2694,8 +2679,7 @@ body {
'> <html>\n' +
'> <style itemProp="foo">' +
'\n' +
'\n in style (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
'\n in style (at **)',
]);
});
@ -2720,8 +2704,7 @@ body {
'> <html>\n' +
'> <link itemProp="foo">\n' +
'\n' +
' in link (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
' in link (at **)',
]);
});
@ -2746,8 +2729,7 @@ body {
'> <html>\n' +
'> <script itemProp="foo">\n' +
'\n' +
' in script (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
' in script (at **)',
]);
});
@ -4844,9 +4826,6 @@ body {
'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' +
' in style (at **)\n' +
(gate('enableOwnerStacks')
? ''
: ' in body (at **)\n' + ' in html (at **)\n') +
' in App (at **)',
]);
@ -7753,64 +7732,43 @@ body {
'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, ' +
'otherwise remove the `precedence` prop.\n' +
' in link (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
' in link (at **)',
'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. ' +
'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, ' +
'otherwise remove the `precedence` prop.\n' +
' in link (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
' in link (at **)',
'An empty string ("") was passed to the href attribute. ' +
'To fix this, either do not render the element at all or ' +
'pass null to href instead of an empty string.\n' +
' in link (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
' in link (at **)',
'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and ' +
'`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 ' +
'and React will not hoist or deduplicate this stylesheet. ' +
'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' +
' in link (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
' in link (at **)',
'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and ' +
'`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 ' +
'React will not hoist or deduplicate this stylesheet. ' +
'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' +
' in link (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
' in link (at **)',
'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 ' +
'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` ' +
'prop remove the `onError` prop, otherwise remove the `precedence` prop.\n' +
' in link (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
' in link (at **)',
'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 ' +
'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` ' +
'prop remove the `disabled` prop, otherwise remove the `precedence` prop.\n' +
' in link (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
' in link (at **)',
].filter(Boolean),
);
@ -7836,8 +7794,7 @@ body {
'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` ' +
'prop remove the `onLoad` and `onError` props, otherwise remove the `precedence` prop.\n' +
' in body (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
' in body (at **)',
]);
});
@ -8429,10 +8386,7 @@ background-color: green;
'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. ' +
'The href for the <style> where this ocurred is "foo bar".\n' +
' in style (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n in body (at **)' + '\n in html (at **)'),
' in style (at **)',
]);
});
});

View File

@ -391,8 +391,7 @@ describe('ReactDOMForm', () => {
'> <form action={function outerAction}>\n' +
' <input>\n' +
'> <form action={function innerAction} ref={{current:null}}>\n' +
'\n in form (at **)' +
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in form (at **)'),
'\n in form (at **)',
]);
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. ' +
'React needs it to encode which action should be invoked. ' +
'It will get overridden.\n' +
' in input (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in form (at **)'),
' in input (at **)',
]);
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. ' +
'For details, see https://react.dev/link/attribute-behavior \n' +
' in button (at **)\n' +
(gate('enableOwnerStacks') ? '' : ' in form (at **)\n') +
' in App (at **)',
]);
await submit(buttonRef.current);

View File

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

View File

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

View File

@ -995,18 +995,6 @@ describe('ReactDOMServerIntegration', () => {
async render => {
let 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);
},
'Element type is invalid: expected a string (for built-in components) or a class/function ' +
@ -1022,16 +1010,6 @@ describe('ReactDOMServerIntegration', () => {
async render => {
let NullComponent = null;
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);
},
'Element type is invalid: expected a string (for built-in components) or a class/function ' +
@ -1043,19 +1021,6 @@ describe('ReactDOMServerIntegration', () => {
async render => {
let UndefinedComponent = undefined;
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);
},
'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 ' +
'the server. This is a no-op.\n\n' +
'Please check the code for the Outer component.\n' +
(gate('enableOwnerStacks') ? '' : ' in Inner (at **)\n') +
' 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. " +
'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' +
(gate('enableOwnerStacks')
? ''
: ' in Child (at **)\n' +
' in Suspense (at **)\n' +
' in div (at **)\n') +
' in App (at **)',
]);

View File

@ -171,8 +171,7 @@ describe('ReactDOM HostSingleton', () => {
'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, ' +
'ensure any previous ones have unmounted first.\n' +
' in head (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in html (at **)'),
' in head (at **)',
]);
expect(getVisibleChildren(document)).toEqual(
<html>

View File

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

View File

@ -2381,17 +2381,6 @@ describe('ReactErrorBoundaries', () => {
'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 () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
@ -2403,18 +2392,6 @@ describe('ReactErrorBoundaries', () => {
'expected a string (for built-in components) or a ' +
'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 () => {

View File

@ -116,7 +116,6 @@ describe('ReactFunctionComponent', () => {
' in GrandParent (at **)',
'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' +
(gate('enableOwnerStacks') ? '' : ' in Child (at **)\n') +
' in Parent (at **)\n' +
' in GrandParent (at **)',
]);
@ -260,7 +259,6 @@ describe('ReactFunctionComponent', () => {
' in Parent (at **)',
'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' +
' in Child (at **)\n' +
' in Parent (at **)',
]);
expect(el.textContent).toBe('en');

View File

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

View File

@ -104,16 +104,10 @@ describe('ReactLegacyContextDisabled', () => {
' in LegacyProvider (at **)',
'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' +
' in LegacyClsConsumer (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n' + ' in span (at **)\n' + ' in LegacyProvider (at **)'),
' in LegacyClsConsumer (at **)',
'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' +
' in LegacyFnConsumer (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n' + ' in span (at **)\n' + ' in LegacyProvider (at **)'),
' in LegacyFnConsumer (at **)',
]);
expect(container.textContent).toBe('{}undefinedundefined');
expect(lifecycleContextLog).toEqual([]);
@ -151,16 +145,10 @@ describe('ReactLegacyContextDisabled', () => {
' in LegacyProvider (at **)',
'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' +
' in LegacyClsConsumer (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n' + ' in span (at **)\n' + ' in LegacyProvider (at **)'),
' in LegacyClsConsumer (at **)',
'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' +
' in LegacyFnConsumer (at **)' +
(gate('enableOwnerStacks')
? ''
: '\n' + ' in span (at **)\n' + ' in LegacyProvider (at **)'),
' in LegacyFnConsumer (at **)',
]);
expect(text).toBe('<span>{}<!-- -->undefined<!-- -->undefined</span>');
expect(lifecycleContextLog).toEqual([{}, {}, {}]);

View File

@ -2112,16 +2112,6 @@ describe('ReactLegacyErrorBoundaries', () => {
ReactDOM.render(<X />, container);
});
}).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 () => {
const container = document.createElement('div');
@ -2129,16 +2119,6 @@ describe('ReactLegacyErrorBoundaries', () => {
ReactDOM.render(<Y />, container);
});
}).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

View File

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

View File

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

View File

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

View File

@ -121,34 +121,20 @@ describe('validateDOMNesting', () => {
);
expectWarnings(
['div', 'ul', 'li', 'div', 'li'],
gate(flags => flags.enableOwnerStacks)
? [
'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 **)',
'<li> cannot contain a nested <li>.\nSee this log for the ancestor stack trace.\n' +
' 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 **)',
],
[
'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 **)',
'<li> cannot contain a nested <li>.\nSee this log for the ancestor stack trace.\n' +
' in li (at **)',
],
);
expectWarnings(
['div', 'html'],
@ -208,28 +194,16 @@ describe('validateDOMNesting', () => {
);
expectWarnings(
['svg', 'foreignObject', 'body', 'p'],
gate(flags => flags.enableOwnerStacks)
? [
// 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 **)',
]
: [
// 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 **)',
],
[
// 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 **)',
],
);
});

View File

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

View File

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

View File

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

View File

@ -47,7 +47,6 @@ import isArray from 'shared/isArray';
import {
enableAsyncIterableChildren,
disableLegacyMode,
enableOwnerStacks,
} from 'shared/ReactFeatureFlags';
import {
@ -488,9 +487,7 @@ function createChildReconciler(
if (__DEV__) {
// We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber;
if (enableOwnerStacks) {
created._debugTask = returnFiber._debugTask;
}
created._debugTask = returnFiber._debugTask;
created._debugInfo = currentDebugInfo;
}
return created;
@ -609,9 +606,7 @@ function createChildReconciler(
if (__DEV__) {
// We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber;
if (enableOwnerStacks) {
created._debugTask = returnFiber._debugTask;
}
created._debugTask = returnFiber._debugTask;
created._debugInfo = currentDebugInfo;
}
return created;
@ -649,9 +644,7 @@ function createChildReconciler(
if (__DEV__) {
// We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber;
if (enableOwnerStacks) {
created._debugTask = returnFiber._debugTask;
}
created._debugTask = returnFiber._debugTask;
created._debugInfo = currentDebugInfo;
}
return created;
@ -718,9 +711,7 @@ function createChildReconciler(
if (__DEV__) {
// We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber;
if (enableOwnerStacks) {
created._debugTask = returnFiber._debugTask;
}
created._debugTask = returnFiber._debugTask;
const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
created._debugInfo = currentDebugInfo;
currentDebugInfo = prevDebugInfo;
@ -1605,9 +1596,7 @@ function createChildReconciler(
if (__DEV__) {
// We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber;
if (enableOwnerStacks) {
created._debugTask = returnFiber._debugTask;
}
created._debugTask = returnFiber._debugTask;
created._debugInfo = currentDebugInfo;
}
return created;
@ -1685,9 +1674,7 @@ function createChildReconciler(
if (__DEV__) {
// We treat the parent as the owner for stack purposes.
created._debugOwner = returnFiber;
if (enableOwnerStacks) {
created._debugTask = returnFiber._debugTask;
}
created._debugTask = returnFiber._debugTask;
created._debugInfo = currentDebugInfo;
}
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
// a promise started from a different component/task.
throwFiber._debugOwner = returnFiber._debugOwner;
if (enableOwnerStacks) {
throwFiber._debugTask = returnFiber._debugTask;
}
throwFiber._debugTask = returnFiber._debugTask;
if (debugInfo != null) {
for (let i = debugInfo.length - 1; i >= 0; i--) {
if (typeof debugInfo[i].stack === 'string') {
throwFiber._debugOwner = (debugInfo[i]: any);
if (enableOwnerStacks) {
throwFiber._debugTask = debugInfo[i].debugTask;
}
throwFiber._debugTask = debugInfo[i].debugTask;
break;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -18,8 +18,6 @@ import reportGlobalError from 'shared/reportGlobalError';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import {bindToConsole} from './ReactFiberConfig';
// 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' +
'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 {
console.warn(
'%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.
);
} finally {
if (!enableOwnerStacks) {
ReactSharedInternals.getCurrentStack = prevGetCurrentStack;
}
// ignore
}
}
}
@ -97,18 +81,6 @@ export function defaultOnCaughtError(
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 {
if (
typeof error === 'object' &&
@ -138,9 +110,7 @@ export function defaultOnCaughtError(
);
}
} finally {
if (!enableOwnerStacks) {
ReactSharedInternals.getCurrentStack = prevGetCurrentStack;
}
// ignore
}
} else {
// In production, we print the error directly.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1222,8 +1222,7 @@ describe('ReactIncrementalErrorHandling', () => {
' in Provider (at **)',
'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' +
' in Connector (at **)' +
(gate('enableOwnerStacks') ? '' : '\n in Provider (at **)'),
' in Connector (at **)',
]);
// If the context stack does not unwind, span will get 'abcde'
@ -1254,23 +1253,6 @@ describe('ReactIncrementalErrorHandling', () => {
</ErrorBoundary>,
);
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(
<span
@ -1319,23 +1301,7 @@ describe('ReactIncrementalErrorHandling', () => {
</ErrorBoundary>,
);
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(
<span
prop={
@ -1354,17 +1320,6 @@ describe('ReactIncrementalErrorHandling', () => {
it('recovers from uncaught reconciler errors', async () => {
const InvalidType = undefined;
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(
'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.
// expect.stringMatching(
// new RegExp(
// gate(flags => flags.enableOwnerStacks)
// ? '\\s+(in|at) ErrorThrowingComponent'
// : '\\s+(in|at) ErrorThrowingComponent (.*)\n' +
// '\\s+(in|at) span(.*)\n' +
// '\\s+(in|at) div(.*)',
// '\\s+(in|at) ErrorThrowingComponent'
// ),
// ),
);
@ -143,11 +139,7 @@ describe('ReactIncrementalErrorLogging', () => {
// The component stack is not added without the polyfill/devtools.
// expect.stringMatching(
// new RegExp(
// gate(flags => flags.enableOwnerStacks)
// ? '\\s+(in|at) ErrorThrowingComponent'
// : '\\s+(in|at) ErrorThrowingComponent (.*)\n' +
// '\\s+(in|at) span(.*)\n' +
// '\\s+(in|at) div(.*)',
// '\\s+(in|at) ErrorThrowingComponent'
// ),
// ),
);
@ -204,12 +196,7 @@ describe('ReactIncrementalErrorLogging', () => {
// The component stack is not added without the polyfill/devtools.
// expect.stringMatching(
// new RegExp(
// gate(flags => flags.enableOwnerStacks)
// ? '\\s+(in|at) ErrorThrowingComponent'
// : '\\s+(in|at) ErrorThrowingComponent (.*)\n' +
// '\\s+(in|at) span(.*)\n' +
// '\\s+(in|at) ErrorBoundary(.*)\n' +
// '\\s+(in|at) div(.*)',
// '\\s+(in|at) ErrorThrowingComponent'
// ),
// ),
);
@ -287,11 +274,7 @@ describe('ReactIncrementalErrorLogging', () => {
),
// The component stack is not added without the polyfill/devtools.
// expect.stringMatching(
// gate(flag => flag.enableOwnerStacks)
// ? new RegExp('\\s+(in|at) Foo')
// : new RegExp(
// '\\s+(in|at) Foo (.*)\n' + '\\s+(in|at) ErrorBoundary(.*)',
// ),
// new RegExp('\\s+(in|at) Foo')
// ),
);
} else {

View File

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

View File

@ -407,12 +407,22 @@ describe('memo', () => {
);
});
assertLog(['Loading...', 15]);
assertConsoleErrorDev([
'Counter: Support for defaultProps will be removed from memo components in a future major release. ' +
'Use JavaScript default parameters instead.\n' +
(label === 'lazy' ? '' : ' in Indirection (at **)\n') +
' in Suspense (at **)',
]);
if (label === 'lazy') {
assertConsoleErrorDev(
[
'Counter: Support for defaultProps will be removed from memo components in a future major release. ' +
'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} />);
// Should bail out because props have not changed
@ -475,12 +485,14 @@ describe('memo', () => {
</div>,
);
});
assertConsoleErrorDev([
'Inner: ' +
'Support for defaultProps will be removed from memo components in a future major release. ' +
'Use JavaScript default parameters instead.\n' +
' in div (at **)',
]);
assertConsoleErrorDev(
[
'Inner: ' +
'Support for defaultProps will be removed from memo components in a future major release. ' +
'Use JavaScript default parameters instead.',
],
{withoutStack: true},
);
expect(root).toMatchRenderedOutput(<div>111</div>);
await act(async () => {
@ -576,9 +588,7 @@ describe('memo', () => {
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' +
(gate('enableOwnerStacks')
? ' in **/ReactMemo-test.js:**:** (at **)'
: ' in p (at **)'),
' in **/ReactMemo-test.js:**:** (at **)',
]);
});
@ -597,8 +607,7 @@ describe('memo', () => {
'\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' +
' in span (at **)\n' +
' in Inner (at **)' +
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
' in Inner (at **)',
]);
});
@ -619,8 +628,7 @@ describe('memo', () => {
'\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' +
' in span (at **)\n' +
' in Inner (at **)' +
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
' in Inner (at **)',
]);
});
@ -640,8 +648,7 @@ describe('memo', () => {
'\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' +
' in span (at **)\n' +
' in Outer (at **)' +
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
' in Outer (at **)',
]);
});
@ -663,8 +670,7 @@ describe('memo', () => {
'\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' +
' in span (at **)\n' +
' in Inner (at **)' +
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
' in Inner (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 () => {
let stack;
@ -75,7 +75,7 @@ describe('ReactOwnerStacks', () => {
it('returns null outside of render', async () => {
// Awkward to gate since some builds will have `captureOwnerStack` return null in prod
if (__DEV__ && gate('enableOwnerStacks')) {
if (__DEV__) {
expect(React.captureOwnerStack()).toBe(null);
await act(() => {

View File

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

View File

@ -1170,25 +1170,15 @@ describe('ReactFlightDOMBrowser', () => {
);
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(() => {
root.render(result);
});
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ParentClient>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]);
}
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ParentClient>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]);
});
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 () => {
let stack;

View File

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

View File

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

View File

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

View File

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

View File

@ -7,18 +7,17 @@
* @flow
*/
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals';
export function captureOwnerStack(): null | string {
if (!enableOwnerStacks || !__DEV__) {
return null;
if (__DEV__) {
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;
}
// 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();
return null;
}

View File

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

View File

@ -333,16 +333,6 @@ describe('ReactChildren', () => {
}
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);
@ -369,8 +359,7 @@ describe('ReactChildren', () => {
'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.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)' +
(gate(flag => flag.enableOwnerStacks) ? '' : '\n in div (at **)'),
' in div (at **)',
]);
});
@ -894,22 +883,13 @@ describe('ReactChildren', () => {
</ComponentRenderingMappedChildren>,
);
});
assertConsoleErrorDev(
gate(flags => flags.enableOwnerStacks)
? [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `ComponentRenderingMappedChildren`.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' 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 **)',
],
);
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `ComponentRenderingMappedChildren`.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)\n' +
' in **/ReactChildren-test.js:**:** (at **)',
]);
});
it('does not warn for mapped static children without keys', async () => {
@ -953,21 +933,12 @@ describe('ReactChildren', () => {
</ComponentRenderingClonedChildren>,
);
});
assertConsoleErrorDev(
gate(flags => flags.enableOwnerStacks)
? [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `ComponentRenderingClonedChildren`.' +
' 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 **)',
],
);
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `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 () => {
@ -1005,21 +976,12 @@ describe('ReactChildren', () => {
</ComponentRenderingFlattenedChildren>,
);
});
assertConsoleErrorDev(
gate(flags => flags.enableOwnerStacks)
? [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `ComponentRenderingFlattenedChildren`.' +
' 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 **)',
],
);
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `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 () => {

View File

@ -266,26 +266,14 @@ describe 'ReactCoffeeScriptClass', ->
test React.createElement(Outer), 'SPAN', 'foo'
if featureFlags.enableOwnerStacks
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 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 **)',
]);
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 Outer (at **)',
]);
it 'renders only once when setting state in componentWillMount', ->
renderCount = 0
@ -578,24 +566,13 @@ describe 'ReactCoffeeScriptClass', ->
React.createElement Bar
test React.createElement(Foo), 'DIV', 'bar-through-context'
if featureFlags.enableOwnerStacks
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 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 **)'
]
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 Foo (at **)'
]
undefined

View File

@ -78,9 +78,7 @@ describe('ReactContextValidator', () => {
' in ComponentInFooBarContext (at **)',
'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' +
(gate(flags => flags.enableOwnerStacks)
? ' in ComponentInFooBarContext (at **)'
: ' in Component (at **)'),
' in ComponentInFooBarContext (at **)',
]);
expect(instance.childRef.current.context).toEqual({foo: 'abc'});
});
@ -159,9 +157,7 @@ describe('ReactContextValidator', () => {
' in Parent (at **)',
'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' +
(gate(flags => flags.enableOwnerStacks)
? ' in Parent (at **)'
: ' in Component (at **)'),
' in Parent (at **)',
]);
expect(constructorContext).toEqual({foo: 'abc'});
@ -282,21 +278,12 @@ describe('ReactContextValidator', () => {
' in ParentContextProvider (at **)',
'MiddleMissingContext uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in MiddleMissingContext (at **)\n') +
' in ParentContextProvider (at **)',
'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' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in MiddleMissingContext (at **)\n') +
' in ParentContextProvider (at **)',
'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' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in ChildContextConsumer (at **)\n') +
' in MiddleMissingContext (at **)\n' +
' in ParentContextProvider (at **)',
]);

View File

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

View File

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

View File

@ -305,9 +305,6 @@ describe('ReactES6Class', () => {
' 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' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Foo (at **)\n') +
' in Outer (at **)',
]);
});
@ -638,9 +635,6 @@ describe('ReactES6Class', () => {
' 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' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Bar (at **)\n') +
' in Foo (at **)',
]);
});

View File

@ -46,19 +46,11 @@ describe('ReactElementValidator', () => {
]),
),
);
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' +
' 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 **)',
],
);
assertConsoleErrorDev([
'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 **)',
]);
});
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)));
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.' +
'\n\nCheck the render method of `' +
(gate(flags => flags.enableOwnerStacks)
? 'ComponentClass'
: 'InnerClass') +
'`. ' +
'\n\nCheck the render method of `ComponentClass`. ' +
'It was passed a child from ComponentWrapper. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
(gate(flags => flags.enableOwnerStacks)
? ' in ComponentWrapper (at **)'
: ' in ComponentClass (at **)\n' +
' in InnerClass (at **)\n' +
' in ComponentWrapper (at **)'),
' in ComponentWrapper (at **)',
]);
});
@ -109,16 +93,12 @@ describe('ReactElementValidator', () => {
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => root.render(<Anonymous>{divs}</Anonymous>));
assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks)
? // For owner stacks the parent being validated is the div.
'Each child in a list should have a unique ' +
'"key" prop.' +
'\n\nCheck the top-level render call using <div>. ' +
'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. See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
// For owner stacks the parent being validated is the div.
'Each child in a list should have a unique ' +
'"key" prop.' +
'\n\nCheck the top-level render call using <div>. ' +
'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' +
' in div (at **)\n' +
' in Component (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Parent (at **)\n') +
' in GrandParent (at **)',
]);
});
@ -206,35 +183,12 @@ describe('ReactElementValidator', () => {
await act(() =>
root.render(React.createElement(ComponentClass, null, iterable)),
);
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. ' +
'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 **)',
],
);
assertConsoleErrorDev([
'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 **)',
]);
});
it('does not warns for arrays of elements with keys', () => {
@ -373,13 +327,6 @@ describe('ReactElementValidator', () => {
];
for (let i = 0; i < cases.length; i++) {
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(
@ -468,21 +415,6 @@ describe('ReactElementValidator', () => {
'or a class/function (for composite components) but got: null.' +
(__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 () => {
@ -559,18 +491,6 @@ describe('ReactElementValidator', () => {
it('does not blow up on key warning with undefined type', () => {
const Foo = undefined;
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', () => {

View File

@ -49,13 +49,9 @@ describe('ReactJSXElementValidator', () => {
root.render(<Component>{[<Component />, <Component />]}</Component>);
});
assertConsoleErrorDev([
gate(flags => flags.enableOwnerStacks)
? '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 **)'
: '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 **)',
]);
});
@ -79,17 +75,9 @@ describe('ReactJSXElementValidator', () => {
});
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.' +
'\n\nCheck the render method of `' +
(gate(flag => flag.enableOwnerStacks)
? 'Component'
: 'InnerComponent') +
'`. ' +
'\n\nCheck the render method of `Component`. ' +
'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 Component (at **)\n' +
' in InnerComponent (at **)\n' +
' in ComponentWrapper (at **)'),
' in ComponentWrapper (at **)',
]);
});
@ -112,34 +100,12 @@ describe('ReactJSXElementValidator', () => {
await act(() => {
root.render(<Component>{iterable}</Component>);
});
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. ' +
'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 **)',
],
);
assertConsoleErrorDev([
'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 **)',
]);
});
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 ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://react.dev/link/special-props)\n' +
(gate(flags => flags.enableOwnerStacks)
? ' in Parent (at **)'
: ' in Child (at **)\n' +
' in div (at **)\n' +
' in Parent (at **)'),
' in Parent (at **)',
]);
});
@ -279,9 +275,6 @@ describe('ReactJSXRuntime', () => {
assertConsoleErrorDev([
'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' +
(gate(flags => flags.enableOwnerStacks)
? ''
: ' in Child (at **)\n') +
' in Parent (at **)',
]);
});

View File

@ -1042,67 +1042,30 @@ describe('context legacy', () => {
root.render(<Root />);
});
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'LegacyContextProvider uses the legacy childContextTypes API ' +
'which will soon be removed. Use React.createContext() instead. ' +
'(https://react.dev/link/legacy-context)' +
'\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 LegacyContextProvider (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 LegacyContextProvider (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 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 **)',
]);
}
assertConsoleErrorDev([
'LegacyContextProvider uses the legacy childContextTypes API ' +
'which will soon be removed. Use React.createContext() instead. ' +
'(https://react.dev/link/legacy-context)' +
'\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 LegacyContextProvider (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 LegacyContextProvider (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 Root (at **)',
]);
// Dedupe
await act(() => {

View File

@ -528,10 +528,7 @@ describe('ReactTypeScriptClass', function () {
' in ProvideChildContextTypes (at **)',
'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' +
(ReactFeatureFlags.enableOwnerStacks
? ' in ProvideChildContextTypes.createElement (at **)'
: ' in StateBasedOnContext (at **)\n') +
' in ProvideChildContextTypes (at **)',
' in ProvideChildContextTypes.createElement (at **)',
]);
});
}
@ -724,10 +721,7 @@ describe('ReactTypeScriptClass', function () {
' in ProvideContext (at **)',
'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' +
(ReactFeatureFlags.enableOwnerStacks
? ' in ProvideContext.createElement (at **)'
: ' in ReadContext (at **)\n') +
' in ProvideContext (at **)',
' in ProvideContext.createElement (at **)',
]);
});
}

View File

@ -348,14 +348,10 @@ describe('create-react-class-integration', () => {
root.render(<Outer />);
});
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.',
),
[
'Component uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
{withoutStack: true},
],
'Component uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
]);
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. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' +
(gate(flags => flags.enableOwnerStacks)
? ' in **/forwardRef-test.js:**:** (at **)'
: ' in p (at **)'),
' in **/forwardRef-test.js:**:** (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). ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' +
' in Inner (at **)' +
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
' in Inner (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). ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in span (at **)\n' +
' in Inner (at **)' +
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
' in Inner (at **)',
]);
});
@ -278,8 +274,7 @@ describe('forwardRef', () => {
'\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' +
' in span (at **)\n' +
' in Outer (at **)' +
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
' in Outer (at **)',
]);
});
@ -301,8 +296,7 @@ describe('forwardRef', () => {
'\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' +
' in span (at **)\n' +
' in Inner (at **)' +
(gate(flags => flags.enableOwnerStacks) ? '' : '\n in p (at **)'),
' in Inner (at **)',
]);
});

View File

@ -10,25 +10,17 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
import hasOwnProperty from 'shared/hasOwnProperty';
import assign from 'shared/assign';
import {
getIteratorFn,
REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE,
REACT_LAZY_TYPE,
} from 'shared/ReactSymbols';
import {checkKeyStringCoercion} from 'shared/CheckStringCoercion';
import isValidElementType from 'shared/isValidElementType';
import isArray from 'shared/isArray';
import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
import {
disableDefaultPropsExceptForClasses,
enableOwnerStacks,
} from 'shared/ReactFeatureFlags';
const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference');
import {disableDefaultPropsExceptForClasses} from 'shared/ReactFeatureFlags';
const createTask =
// 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
console.createTask
: () => null;
@ -261,20 +253,18 @@ function ReactElement(
writable: true,
value: null,
});
if (enableOwnerStacks) {
Object.defineProperty(element, '_debugStack', {
configurable: false,
enumerable: false,
writable: true,
value: debugStack,
});
Object.defineProperty(element, '_debugTask', {
configurable: false,
enumerable: false,
writable: true,
value: debugTask,
});
}
Object.defineProperty(element, '_debugStack', {
configurable: false,
enumerable: false,
writable: true,
value: debugStack,
});
Object.defineProperty(element, '_debugTask', {
configurable: false,
enumerable: false,
writable: true,
value: debugTask,
});
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
@ -390,8 +380,8 @@ export function jsxProdSignatureRunningInDevWithDynamicChildren(
isStaticChildren,
source,
self,
__DEV__ && enableOwnerStacks ? Error('react-stack-top-frame') : undefined,
__DEV__ && enableOwnerStacks ? createTask(getTaskName(type)) : undefined,
__DEV__ && Error('react-stack-top-frame'),
__DEV__ && createTask(getTaskName(type)),
);
}
}
@ -412,8 +402,8 @@ export function jsxProdSignatureRunningInDevWithStaticChildren(
isStaticChildren,
source,
self,
__DEV__ && enableOwnerStacks ? Error('react-stack-top-frame') : undefined,
__DEV__ && enableOwnerStacks ? createTask(getTaskName(type)) : undefined,
__DEV__ && Error('react-stack-top-frame'),
__DEV__ && createTask(getTaskName(type)),
);
}
}
@ -434,8 +424,8 @@ export function jsxDEV(type, config, maybeKey, isStaticChildren, source, self) {
isStaticChildren,
source,
self,
__DEV__ && enableOwnerStacks ? Error('react-stack-top-frame') : undefined,
__DEV__ && enableOwnerStacks ? createTask(getTaskName(type)) : undefined,
__DEV__ && Error('react-stack-top-frame'),
__DEV__ && createTask(getTaskName(type)),
);
}
@ -450,80 +440,37 @@ function jsxDEVImpl(
debugTask,
) {
if (__DEV__) {
if (!enableOwnerStacks && !isValidElementType(type)) {
// This is an invalid element type.
//
// 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.";
}
// We don't warn for invalid element type here because with owner stacks,
// 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.
let typeString;
if (type === null) {
typeString = 'null';
} else if (isArray(type)) {
typeString = 'array';
} else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {
typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`;
info =
' Did you accidentally export a JSX literal instead of a component?';
} else {
typeString = typeof 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.)
// With owner stacks, 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);
}
console.error(
'React.jsx: 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.)
// 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.',
);
if (Object.freeze) {
Object.freeze(children);
}
} 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) {
if (__DEV__) {
if (!enableOwnerStacks && !isValidElementType(type)) {
// This is just an optimistic check that provides a better stack trace before
// owner stacks. It's really up to the renderer if it's a valid element type.
// 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.";
}
// We don't warn for invalid element type here because with owner stacks,
// 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.
let typeString;
if (type === null) {
typeString = 'null';
} else if (isArray(type)) {
typeString = 'array';
} else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {
typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`;
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);
}
// 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.
@ -795,8 +700,8 @@ export function createElement(type, config, children) {
undefined,
getOwner(),
props,
__DEV__ && enableOwnerStacks ? Error('react-stack-top-frame') : undefined,
__DEV__ && enableOwnerStacks ? createTask(getTaskName(type)) : undefined,
__DEV__ && Error('react-stack-top-frame'),
__DEV__ && createTask(getTaskName(type)),
);
}
@ -808,8 +713,8 @@ export function cloneAndReplaceKey(oldElement, newKey) {
undefined,
!__DEV__ ? undefined : oldElement._owner,
oldElement.props,
__DEV__ && enableOwnerStacks ? oldElement._debugStack : undefined,
__DEV__ && enableOwnerStacks ? oldElement._debugTask : undefined,
__DEV__ && oldElement._debugStack,
__DEV__ && oldElement._debugTask,
);
if (__DEV__) {
// The cloned element should inherit the original element's key validation.
@ -914,8 +819,8 @@ export function cloneElement(element, config, children) {
undefined,
owner,
props,
__DEV__ && enableOwnerStacks ? element._debugStack : undefined,
__DEV__ && enableOwnerStacks ? element._debugTask : undefined,
__DEV__ && element._debugStack,
__DEV__ && element._debugTask,
);
for (let i = 2; i < arguments.length; i++) {
@ -936,51 +841,13 @@ export function cloneElement(element, config, children) {
*/
function validateChildKeys(node, parentType) {
if (__DEV__) {
if (enableOwnerStacks) {
// When owner stacks is enabled no warnings happens. All we do is
// mark elements as being in a valid static child position so they
// don't need keys.
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.
// With owner stacks is, no warnings happens. All we do is
// mark elements as being in a valid static child position so they
// don't need keys.
if (isValidElement(node)) {
if (node._store) {
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
);
}
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 {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import {formatOwnerStack} from 'shared/ReactOwnerStackFrames';
export function getOwnerStackByComponentInfoInDev(
componentInfo: ReactComponentInfo,
): string {
if (!enableOwnerStacks || !__DEV__) {
if (!__DEV__) {
return '';
}
try {

View File

@ -7,25 +7,12 @@
* @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 ReactSharedInternals from 'shared/ReactSharedInternals';
import DefaultPrepareStackTrace from 'shared/DefaultPrepareStackTrace';
import {enableViewTransition} from 'shared/ReactFeatureFlags';
let prefix;
let suffix;
export function describeBuiltInComponentFrame(name: string): string {
@ -300,53 +287,3 @@ export function describeClassComponentFrame(ctor: Function): string {
export function describeFunctionComponentFrame(fn: Function): string {
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 enableOwnerStacks = true;
export const enableShallowPropDiffing = false;
export const enableSiblingPrerendering = true;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -36,7 +36,7 @@ import {
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.
// TODO: Delete this when enableOwnerStacks ships.
// TODO: Delete this now that owner stacks shipped.
export default function isValidElementType(type: mixed): boolean {
if (typeof type === 'string' || typeof type === 'function') {
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
// code live.
actual.disableInputAttributeSyncing = __VARIANT__;
actual.enableOwnerStacks = __VARIANT__;
// These are hardcoded to true for the next release,
// 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'
);
actual.enableOwnerStacks = __VARIANT__;
// 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.
// Since the xplat tests run with the www entry points, some of these flags