-
Notifications
You must be signed in to change notification settings - Fork 51k
Warn for keys in fragments - second approach #9434
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
Changes from 5 commits
23252d5
d6cfec8
c4d28a0
398b0fb
c84c0d9
adf9153
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,7 @@ var ReactElement = require('ReactElement'); | |
| var canDefineProperty = require('canDefineProperty'); | ||
| var getComponentName = require('getComponentName'); | ||
| var getIteratorFn = require('getIteratorFn'); | ||
| var validateExplicitKey = require('validateExplicitKey'); | ||
|
|
||
| if (__DEV__) { | ||
| var checkPropTypes = require('checkPropTypes'); | ||
|
|
@@ -58,13 +59,6 @@ function getSourceInfoErrorAddendum(elementProps) { | |
| return ''; | ||
| } | ||
|
|
||
| /** | ||
| * Warn if there's no key explicitly set on dynamic arrays of children or | ||
| * object keys are not valid. This allows us to keep track of children between | ||
| * updates. | ||
| */ | ||
| var ownerHasKeyUseWarning = {}; | ||
|
|
||
| function getCurrentComponentErrorInfo(parentType) { | ||
| var info = getDeclarationErrorAddendum(); | ||
|
|
||
|
|
@@ -80,30 +74,16 @@ function getCurrentComponentErrorInfo(parentType) { | |
| } | ||
|
|
||
| /** | ||
| * 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. | ||
| * Composes the warning that is shown when an element doesn't have an explicit | ||
| * key assigned to it. | ||
| * | ||
| * @internal | ||
| * @param {ReactElement} element Element that requires a key. | ||
| * @param {*} parentType element's parent's type. | ||
| * @param {ReactElement} element Element that requires a key. | ||
| * @return string message that described explicit key error | ||
| */ | ||
| function validateExplicitKey(element, parentType) { | ||
| if (!element._store || element._store.validated || element.key != null) { | ||
| return; | ||
| } | ||
| element._store.validated = true; | ||
|
|
||
| var memoizer = ownerHasKeyUseWarning.uniqueKey || | ||
| (ownerHasKeyUseWarning.uniqueKey = {}); | ||
|
|
||
| function getExplicitKeyErrorMessage(parentType, element) { | ||
| var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); | ||
| if (memoizer[currentComponentErrorInfo]) { | ||
| return; | ||
| } | ||
| memoizer[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 | ||
|
|
@@ -116,14 +96,12 @@ function validateExplicitKey(element, parentType) { | |
| childOwner = ` It was passed a child from ${getComponentName(element._owner)}.`; | ||
| } | ||
|
|
||
| warning( | ||
| false, | ||
| 'Each child in an array or iterator should have a unique "key" prop.' + | ||
| '%s%s See https://fb.me/react-warning-keys for more information.%s', | ||
| currentComponentErrorInfo, | ||
| childOwner, | ||
| getCurrentStackAddendum(element), | ||
| ); | ||
| const message = 'Each child in an array or iterator should have a unique "key" prop.' + | ||
| currentComponentErrorInfo + | ||
| childOwner + | ||
| ' ' + | ||
| 'See https://fb.me/react-warning-keys for more information.'; | ||
| return message; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -143,7 +121,15 @@ function validateChildKeys(node, parentType) { | |
| for (var i = 0; i < node.length; i++) { | ||
| var child = node[i]; | ||
| if (ReactElement.isValidElement(child)) { | ||
| validateExplicitKey(child, parentType); | ||
| const getMainExplicitKeyErrorMessage = getExplicitKeyErrorMessage.bind( | ||
| null, | ||
| parentType, | ||
| ); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if there's a way we could do this without having to create a new function for every child? What if If not, we should move this outside of the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice catch - will fix.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the cleanest option is to just move it outside of the 'for' loop. I'll play around with some alternatives and maybe push another version to see, but I think it will be ugly. |
||
| validateExplicitKey( | ||
| child, | ||
| getMainExplicitKeyErrorMessage, | ||
| getCurrentStackAddendum, | ||
| ); | ||
| } | ||
| } | ||
| } else if (ReactElement.isValidElement(node)) { | ||
|
|
@@ -160,7 +146,15 @@ function validateChildKeys(node, parentType) { | |
| var step; | ||
| while (!(step = iterator.next()).done) { | ||
| if (ReactElement.isValidElement(step.value)) { | ||
| validateExplicitKey(step.value, parentType); | ||
| const getMainExplicitKeyErrorMessage = getExplicitKeyErrorMessage.bind( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. If we bind outside of the loop (maybe at the top of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! Will fix. |
||
| null, | ||
| parentType, | ||
| ); | ||
| validateExplicitKey( | ||
| step.value, | ||
| getMainExplicitKeyErrorMessage, | ||
| getCurrentStackAddendum, | ||
| ); | ||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the policy for committing changes to
results.json? It would be weird ifbranchwas always just the name of the last branch merged into master.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what we do for now. It doesn't really matter and gives us heads up on unexpected changes. Ideally later we'd migrate to another approach (e.g. a bot that comments). But this works okay for now.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So should we be asking contributors to include this in PRs that make changes to code included in bundles? If so I can add it to our PR template for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't we get terrible merge conflicts soon once everyone has a different base here? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tldr; In most cases no, there won't be terrible merge conflicts, and when it happens it should be fairly easy to resolve.
I think I have been in similar situations with generated 'schema' type files, and there can be annoying merge conflicts in some cases.
If people have a stack of commits, and they commit the 'results.json' in each commit, and then rebase, they could have a merge conflict to resolve for each diff.
Ideally they just commit the 'results.json' at the top of their commit stack, and if there is a conflict they can regenerate the file and
git add scripts/rollup/results.json.It would be great to automate this though.