-
Notifications
You must be signed in to change notification settings - Fork 132
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
Spec proposal: extending the language to allow spreading children #57
Comments
When is this a problem (not being snarky)? You may not modify children (it's considered an immutable opaque structure), so passing it through Also, as implemented for React, JSX compiles to a varargs function call which internally only allocates an array for children if there are 2 or more children. For zero or one child they are returned as |
@syranide It’s important to remember that I’m not thinking about this from a React perspective. You’re right in that if JSX were solely for React this change wouldn’t make sense. However, for the greater JSX universe this could be helpful.
The problem is really noticeable when expressing a JSX structure in a type system. In the type system you now need to accommodate what is really an implementation detail in the type grammar. Of course, here I assume that there is no transformation function like ( In addition, if you are going to support this pattern (which JSX is arguably not useful without the idea of an array of children) you must support a post processing layer before your JSX objects are useful. Whether that be on an element level (
But this exactly what this proposal is trying to avoid. The need for a helper function. A helper function may make sense for React, but it adds complexity and weight to lighter implementations using JSX. JSX is very high up on the levels of abstraction, whereas React is a little lower. Ideally JSX consumers shouldn’t have to step down an abstraction level for JSX to be useful.
This is a React optimization. Technical decisions made by React shouldn’t leak up the abstraction chain and block features in JSX. React users need not use this feature if it’s a React anti-pattern. |
If you don't put the burden of flattening the children implicitly on the consumer then it falls on the user of JSX to pre-flatten all children. Definitely a possibility, but it's something that would make certain use-cases very troublesome. Consider It's my opinion, but while that it is in some sense an implementation detail of React, it also influences the JSX syntax. There's always a trade-off between language features and runtime features. Being able to have nested maps/sets/arrays is basically an assumed feature of JSX if you ask me.
Could not translate to It also seems to me the only reason it would be the It's late and I feel like I'm rambling a bit, but it seems to me that all this would be doing is transferring the responsibility of flattening children to the user, explicitly requiring the use of |
I agree. This is the intended nature. Explicit notion over an implicit conversion.
This is a good example, but I’d argue here that I’d rather give this case to the user to optimize instead of assuming every JSX runtime will optimize for. A user that understands their runtime would not write JSX that looks like this. In addition, this proposal would not stop React from optimizing for this case.
This makes two assumptions I: One is that keys are array local. I know I’ve considered instead using Two is the assumption that this is a common case and people will choose to write helpers instead of nesting like so: There are ways to work around this potential performance issue without writing helpers, and if people chose to always use global
Run this code in an ES6 environment: [...new Map([[1, 2], [3, 4]])] The result is Therefore the spread operator (
Yep 😊 And again,
Yes. You can’t do: const foo = [1, 2, 3]
const bar = [4, foo, 5]
assert(bar === [4, 1, 2, 3, 5]) So developers are already expected to spread lists in an array. This proposal is a natural extension of this.
(See my above statement on iterators)
I don’t think so, I only think the practical issues are for React. JSX isn’t exclusively for React (or at least I hope). If this proposal gets implemented in |
Ah, my bad :) Anyway, I can imagine some alternate use-cases where it makes sense to allow the user to produce children output without nesting (to produce exact data structures) and it seems like a natural and harmless extension in itself, so IMHO it's seems sane as presented and fine to me (but it's not my decision). So have a 👍 from me. I imagine your best bet moving forward would be to just implement/fork the babel extension and see if you can drum up support that way. It's always easier pushing something through if you can prove there's actually a real-life benefit/demand here. |
cc @sebmarkbage If you have the time, any thoughts? |
I always intended for opening up this syntax. It is the reason spread of attributes is I'd be fine supporting this in the JSX syntax specification but disallowing it in the React implementation, or simply treat it the same as The key issue very complex and way beyond the scope of this thread, but needless to say, if we thought any of the proposed alternative were better than the complex nested data structure we'd prefer it.
Note that createElement doesn't really do anything that can't be statically known other than the defaultProps. So the idea is that you should be able to translate these into POJOs even for React. I'd love to get to a point where implementations can agree on a format of this POJO but this is probably a key point preventing this from happening (pun intended). |
Opened a PR in babel/babylon#42 to implement this functionality. @kittens wants to see it properly specced in this repo first which is understandable. Do you want me to proceed with a PR to this repo, or would you like to see the |
A PR here seems fine. Seems pretty non-controversial. |
Done. |
I propose we modify the JSX specification to allow for the spreading of child nodes in JSX like so:
Instead of the implicit array flattening done by React and other JSX consumers currently.
Rationale
JSX with React allows you to do this:
However, React cleverly hides what is actually happening. If we turn the above JSX into a static object, we get something that looks like this:
As you can see we have a nested array:
This requires JSX consumers to flatten arrays before processing them. A step that is not only unnecessary but also difficult to express in a JSX type system that would otherwise look like a tree.
Must instead become something to the effects of:
It’s strange that we should have this problem, however, when the solution should really be in the language. Already ES6 has introduced the spread operator (
...
), so modifying our above example to:Will give us the list of list of children the JSX consumer needs without requiring a post processing step. We add the expressiveness to the language and we remove complexity from our JSX consuming libraries (like React).
In order to add this extension, we just extend JSXChild to allow for the type
{
...
AssignmentExpression(opt)}
.Then the above example would become:
Or the classic
children
example would be:And this would compile to a form we expect at a type level:
Motivation
React isn’t the only library/framework which should be able to consume JSX, and we shouldn’t expect every library/framework to adopt React’s JSX “workaround” of flattening child arrays when in fact that is a fault in the language extension.
Therefore, in order to simplify libraries and avoid extra complexity in JSX consumers we should implement this proposal.
Next Steps
I wanted to submit this proposal here to see if anyone had opinions on it before I started writing code. In the near future I will probably submit a PR to the Babel repository modifying the
babel-plugin-syntax-jsx
plugin adding this change. After that PR I will implement a transform in my general JSX transformation librarybabel-plugin-transform-jsx
. If both experiments are successful we can consider adding the child spread functionality to the JSX spec and other JSX transpilers.Thanks!
The text was updated successfully, but these errors were encountered: