-
Notifications
You must be signed in to change notification settings - Fork 47k
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
Warn if people mutate children. #7001
Conversation
I've never seen this. You mean they're mutating the array that React.createElement makes? Can we just freeze it instead? Public API so @facebook/react-core. |
But yeah, they're mutating the props.children array. It's terrible. |
createElement does create an array when you use the var args. We could probably freeze that one. Needs to be tracked first if it is common though. When people mutate their children what's the common pattern? Do these gets stored in state with elements? That seems fine(ish). Probably used as a perf optimization by experts. Or is it data stored in state which gets mutated by render to override it with elements? I assume a common one is that a wrapper adds children to an existing set. |
Yes, it is usually when a wrapper is mutating their props.children array. I've also seen:
I've also seen cases where the element is created, and elsewhere in the code (internally, UFI) there is logic to push elements into the array. It was a readability disaster of epic proportions. |
Also, where is varargs? Signature of |
We could update the signature to |
Ok, yeah, I'm fine with freezing that array. Either way, we probably want to warn for a release before breaking people's apps, right? I don't really care, if you guys want to turn this into a breaking change, that's fine with me. Just let me know how to update the PR to move this forward. |
31ebcb7
to
d831436
Compare
Ping @sebmarkbage, as per team sync. |
@jimfb updated the pull request. |
Even if it takes an array I don't see the problem. Contractually you're required to not mutate the array so ownership is effectively transferred to React anyway and it should be free to freeze it. Right? |
If it's frozen, it'll show nothing in loose mode when trying to mutate, and I think it will be confusing. |
Passing an object to React.createElement does not transfer ownership to React any more than passing the object to |
@jimfb I have to admit I'm not entirely up on the internals here, if modifying If not, then we have previously said that children should be treated equally to other props. Such that children only have special treatment for convenience and passing the same data through other props should exhibit identical behavior. I'm not sure of your stance on the API internally nowadays, but previously, passing varargs or an array was considered synonymous. Freezing varargs would contradict that. For all intents and purposes, children does not need to be renderables and a component getting data through children rather than a prop can be a visual/convenience preference. So if we don't freeze props then freezing children is a bit odd, I agree it makes sense in the overwhelming majority of cases, but IMHO it does contradict "children being just another prop" if we still stand by it. tl;dr I feel like this boils down to whether we find it ok to consider vararg/JSX-children to be special or if they should be straight-up forwarded as an array. Also, what about nested children? EDIT: PS. I'm not against making children special (essentially, they should only be used for renderables), I think it can make a lot of sense, but then perhaps we should be explicit about that too. |
@syranide Conceptually, I agree with you. There are edge cases like someone choosing a different name ( |
@@ -116,6 +116,12 @@ var ReactElement = function(type, key, ref, self, source, owner, props) { | |||
writable: false, | |||
value: self, | |||
}); | |||
Object.defineProperty(element, '_shadowChildren', { |
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.
Define this in the non canDefineProperty case too.
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.
Done.
d831436
to
3204c58
Compare
@jimfb updated the pull request. |
(cherry picked from commit 49238b9)
I wrote a HOC which changes the rendered element-tree: react-native-style-tachyons. I needed a couple of hours to understand whether modifications of props, children etc. is allowed, how to copy See my (unanswered) question on SO: https://stackoverflow.com/questions/37120956/react-cloneelement-pass-new-children-or-copy-props-children Here my code that recursively changes an element-tree, I'm still not completely sure if I'm doing it correctly: https://github.com/tachyons-css/react-native-style-tachyons/blob/master/src/reactWrapper.js#L43 |
I answered the questions in your SO post. |
@spicyj Great thanks. |
Warn if people mutate children.