Skip to content

Commit

Permalink
Add owner based debug information to key warning
Browse files Browse the repository at this point in the history
Now that we have owners in Fizz we can add the missing context in the error
message that the client and jsx had.

I don't think this context is very useful now that we have good stacks but
it is at least parity.
  • Loading branch information
sebmarkbage committed Jul 1, 2024
1 parent 2238497 commit ec4b3fc
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 5 deletions.
4 changes: 1 addition & 3 deletions packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1837,9 +1837,7 @@ describe('ReactDOMFizzServer', () => {
expect(mockError).toHaveBeenCalledWith(
'Each child in a list should have a unique "key" prop.%s%s' +
' See https://react.dev/link/warning-keys for more information.%s',
gate(flags => flags.enableOwnerStacks)
? ''
: '\n\nCheck the render method of `B`.',
'\n\nCheck the render method of `B`.',
'',
'\n' +
(gate(flags => flags.enableOwnerStacks)
Expand Down
39 changes: 37 additions & 2 deletions packages/react-server/src/ReactFizzServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2922,6 +2922,41 @@ function warnForMissingKey(request: Request, task: Task, child: mixed): void {
}
didWarnForKey.add(parentStackFrame);

const componentName = getComponentNameFromType(child.type);
const childOwner = child._owner;
const parentOwner = parentStackFrame.owner;

let currentComponentErrorInfo = '';
if (parentOwner && typeof parentOwner.tag === 'number') {
const name = getComponentNameFromType((parentOwner: any).type);
if (name) {
currentComponentErrorInfo =
'\n\nCheck the render method of `' + name + '`.';
}
}
if (!currentComponentErrorInfo) {
if (componentName) {
currentComponentErrorInfo = `\n\nCheck the top-level render call using <${componentName}>.`;
}
}

// 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 childOwnerAppendix = '';
if (childOwner != null && parentOwner !== childOwner) {
let ownerName = null;
if (typeof childOwner.tag === 'number') {
ownerName = getComponentNameFromType((childOwner: any).type);
} else if (typeof childOwner.name === 'string') {
ownerName = childOwner.name;
}
if (ownerName) {
// Give the component that originally created this child.
childOwnerAppendix = ` It was passed a child from ${ownerName}.`;
}
}

// We create a fake component stack for the child to log the stack trace from.
const stackFrame = createComponentStackFromType(
task,
Expand All @@ -2933,8 +2968,8 @@ function warnForMissingKey(request: Request, task: Task, child: mixed): void {
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,
childOwnerAppendix,
);
task.componentStack = stackFrame.parent;
}
Expand Down

0 comments on commit ec4b3fc

Please sign in to comment.