jsx
jsx copied to clipboard
Proposal: destructuring
Let's say you have a function that returns an object with a known shape that you want to use as props. Currently with JSX, you would use spread:
<Foo {...bar()} />
This is compiled to the following:
React.createElement(Foo, bar());
Great! Now, let's say you want to add some other props to this.
<Foo {...bar()} baz />
When compiling for React, this is compiled to the following:
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
React.createElement(Foo, _extends({}, bar(), { baz: true }));
Which makes sense, but the Object.assign
and _extends
helper code here is a bit of a bummer if you happen to do this all over the place. Granted, there are ways to minimize the helper code, but you still have the overhead of Object.assign
.
It might be nice to have a way to destructure in JSX to avoid this overhead. Here's an idea:
<Foo {fizz, buzz}={bar()} baz />
could compile to something like this:
React.createElement(Foo, (_bar = bar(), { fizz: _bar.fizz, buzz: _bar.buzz, baz: true }));
JSPerf: https://jsperf.com/object-assign-vs-shenanigans/1
This might dovetail well with AssignmentExpression in JSXAttributeName (#21) which is being considered for JSX 2.0 (#65).
I like that this helps to be precise about which props you want to spread (when not all of them). I suspect Flow (by way of users of Flow) might benefit from this precision... cc @samwgoldman
And of course array destructuring could be done similarly:
<Foo [, second, third]={bar()} baz />
becomes
React.createElement(Foo, (_bar = bar(), { second: _bar[1], third: _bar[2], baz: true }));
And assigning to new variable names:
<Foo {fizz: fizzy, buzz: buzzy}={bar()} baz />
becomes
React.createElement(Foo, (_bar = bar(), { fizzy: _bar.fizz, buzzy: _bar.buzz, baz: true }));
I think that maybe it could support default values as well.
<Foo {fizz = 1, buzz = 2}={bar()} baz />
becomes
React.createElement(Foo, (_bar, = bar(), { fizz: _bar.fizz === undefined ? 1 : _bar.fizz, buzz: _bar.buzz === undefined ? 2 : _bar.buzz, baz: true }
Although defaultProps can (and should) be used, at least this gives feature parity with normal destructuring
I think that we'll probably want to align with a proposal to general JS to do this in object literals rather than inventing our own way of doing this that then may get misaligned with a JS solution. Here is a plausible proposal that might satisfy this general use case for object literals:
https://github.com/RReverser/es-borrowed-props
We could do the same for JSX if this proposal advanced in JS.