Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix key Warning for Flattened Positional Children #29662

Merged
merged 2 commits into from
May 30, 2024

Conversation

yungsters
Copy link
Contributor

Summary

#29088 introduced a regression triggering this warning when rendering flattened positional children:

Each child in a list should have a unique "key" prop.

The specific scenario that triggers this is when rendering multiple positional children (which do not require unique key props) after flattening them with one of the React.Children utilities (e.g. React.Children.toArray).

The refactored logic in React.Children incorrectly drops the element._store.validated property in __DEV__. This diff fixes the bug and introduces a unit test to prevent future regressions.

How did you test this change?

$ yarn test ReactChildren-test.js

Copy link

vercel bot commented May 30, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
react-compiler-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 30, 2024 2:23pm

@react-sizebot
Copy link

react-sizebot commented May 30, 2024

Comparing: c2b45ef...49267d4

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.66 kB 6.66 kB +0.11% 1.82 kB 1.82 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 496.38 kB 496.38 kB = 88.84 kB 88.84 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.67 kB 6.67 kB +0.16% 1.82 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 501.20 kB 501.20 kB = 89.53 kB 89.53 kB
facebook-www/ReactDOM-prod.classic.js = 593.81 kB 593.81 kB = 104.45 kB 104.45 kB
facebook-www/ReactDOM-prod.modern.js = 570.20 kB 570.20 kB = 100.85 kB 100.85 kB
test_utils/ReactAllWarnings.js Deleted 63.65 kB 0.00 kB Deleted 15.90 kB 0.00 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-experimental/react/cjs/react.react-server.development.js +0.33% 58.40 kB 58.59 kB +0.32% 16.64 kB 16.69 kB
oss-stable-semver/react/cjs/react.react-server.development.js +0.28% 69.50 kB 69.70 kB +0.28% 19.47 kB 19.52 kB
oss-stable/react/cjs/react.react-server.development.js +0.28% 69.53 kB 69.72 kB +0.29% 19.49 kB 19.55 kB
oss-experimental/react/cjs/react.development.js +0.25% 78.69 kB 78.88 kB +0.24% 21.66 kB 21.71 kB
oss-stable-semver/react/cjs/react.development.js +0.21% 93.90 kB 94.09 kB +0.17% 25.77 kB 25.81 kB
oss-stable/react/cjs/react.development.js +0.21% 93.92 kB 94.12 kB +0.17% 25.80 kB 25.84 kB
test_utils/ReactAllWarnings.js Deleted 63.65 kB 0.00 kB Deleted 15.90 kB 0.00 kB

Generated by 🚫 dangerJS against 49267d4

Copy link
Member

@javache javache left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the changes made in #29088 this makes sense.

Comment on lines +871 to +888
it('does not warn for flattened positional children', async () => {
function ComponentRenderingFlattenedChildren({children}) {
return <div>{React.Children.toArray(children)}</div>;
}

const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render(
<ComponentRenderingFlattenedChildren>
<div />
<div />
</ComponentRenderingFlattenedChildren>,
);
});
}).toErrorDev([]);
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add another example where it does still correctly warn if an array was used without keys?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should have test for this already

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surprisingly, we don't for the simple case. (We do for iterables of children.)

@@ -966,6 +966,11 @@ export function cloneAndReplaceKey(oldElement, newKey) {
__DEV__ && enableOwnerStacks ? oldElement._debugStack : undefined,
__DEV__ && enableOwnerStacks ? oldElement._debugTask : undefined,
);
if (__DEV__) {
// The cloned element should inherit the original element's key validation.
clonedElement._store.validated = oldElement._store.validated;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to check if oldElement._store exists? We do so in other calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that, too.

I don't think it's necessary because we always define it in __DEV__, and we also assume it exists shortly after this method call (when we conditionally set validated to 2).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the other call sites check for _store because they might be receiving malformed elements (e.g. constructed by third party libraries or something).

But here, we are creating clonedElement.

@yungsters yungsters merged commit 72644ef into facebook:main May 30, 2024
39 of 40 checks passed
@yungsters yungsters deleted the key-validation branch May 30, 2024 14:26
github-actions bot pushed a commit that referenced this pull request May 30, 2024
## Summary

#29088 introduced a regression
triggering this warning when rendering flattened positional children:

> Each child in a list should have a unique "key" prop.

The specific scenario that triggers this is when rendering multiple
positional children (which do not require unique `key` props) after
flattening them with one of the `React.Children` utilities (e.g.
`React.Children.toArray`).

The refactored logic in `React.Children` incorrectly drops the
`element._store.validated` property in `__DEV__`. This diff fixes the
bug and introduces a unit test to prevent future regressions.

## How did you test this change?

```
$ yarn test ReactChildren-test.js
```

DiffTrain build for commit 72644ef.
github-actions bot pushed a commit that referenced this pull request May 30, 2024
## Summary

#29088 introduced a regression
triggering this warning when rendering flattened positional children:

> Each child in a list should have a unique "key" prop.

The specific scenario that triggers this is when rendering multiple
positional children (which do not require unique `key` props) after
flattening them with one of the `React.Children` utilities (e.g.
`React.Children.toArray`).

The refactored logic in `React.Children` incorrectly drops the
`element._store.validated` property in `__DEV__`. This diff fixes the
bug and introduces a unit test to prevent future regressions.

## How did you test this change?

```
$ yarn test ReactChildren-test.js
```

DiffTrain build for [72644ef](72644ef)
yungsters added a commit that referenced this pull request May 31, 2024
## Summary

In #29088, the validation logic
for `React.Children` inspected whether `mappedChild` — the return value
of the map callback — has a valid `key`. However, this deviates from
existing behavior which only warns if the original `child` is missing a
required `key`.

This fixes false positive `key` validation warnings when using
`React.Children`, by validating the original `child` instead of
`mappedChild`.

This is a more general fix that expands upon my previous fix in
#29662.

## How did you test this change?

```
$ yarn test ReactChildren-test.js
```
github-actions bot pushed a commit that referenced this pull request May 31, 2024
## Summary

In #29088, the validation logic
for `React.Children` inspected whether `mappedChild` — the return value
of the map callback — has a valid `key`. However, this deviates from
existing behavior which only warns if the original `child` is missing a
required `key`.

This fixes false positive `key` validation warnings when using
`React.Children`, by validating the original `child` instead of
`mappedChild`.

This is a more general fix that expands upon my previous fix in
#29662.

## How did you test this change?

```
$ yarn test ReactChildren-test.js
```

DiffTrain build for commit 8fd963a.
github-actions bot pushed a commit that referenced this pull request May 31, 2024
## Summary

In #29088, the validation logic
for `React.Children` inspected whether `mappedChild` — the return value
of the map callback — has a valid `key`. However, this deviates from
existing behavior which only warns if the original `child` is missing a
required `key`.

This fixes false positive `key` validation warnings when using
`React.Children`, by validating the original `child` instead of
`mappedChild`.

This is a more general fix that expands upon my previous fix in
#29662.

## How did you test this change?

```
$ yarn test ReactChildren-test.js
```

DiffTrain build for [8fd963a](8fd963a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants