Spec proposal: extending the language to allow spreading children · Issue #57 · facebook/jsx (original) (raw)

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:

const TodoList = ({ todos }) => (

{todos.map(todo => )}
)

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:

const TodoList = ({ todos }) => ({ type: 'div', children: [ todos.map(todo => …) ], })

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.

type JSXNode = JSXNodePrimitive | JSXElement

Must instead become something to the effects of:

type JSXNode = JSXNodePrimitive | JSXElement | Iterable

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:

const TodoList = ({ todos }) => ({ type: 'div', children: [ ...todos.map(todo => …) ], })

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:

const TodoList = ({ todos }) => (

{...todos.map(todo => )}
)

Or the classic children example would be:

And this would compile to a form we expect at a type level:

{ kind: 'div', children: [ ...children, ], }

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 library babel-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!