28

Given this example code from the React docs:

var props = {};
props.foo = x;
props.bar = y;
var component = <Component {...props} />;

I did some looking into what ...props actually evaluates to, which is this:

React.__spread({}, props)

Which in turn evaluates to {foo: x, bar: y}.

But what I'm wondering is, why can't I just do this:

var component = <Component props />;

I don't see understand what the point of the spread operator is.

Dmitry Shvedov
  • 3,169
  • 4
  • 39
  • 51
ffxsam
  • 26,428
  • 32
  • 94
  • 144
  • BTW, the spread operator is part of ES6, not just JSX – Dmitry Shvedov Jan 31 '16 at 01:35
  • Technically, [rest-spread for arrays](https://github.com/lukehoban/es6features#default--rest--spread) is officially part of of ES6, but [rest-spread for objects](https://github.com/tc39/proposal-object-rest-spread) is in Stage 3 of the standards approval process. If you want to use it for objects, you have to use at least babel.js preset [stage-3](https://babeljs.io/docs/plugins/preset-stage-3/) or directly [transform-object-rest-spread](https://babeljs.io/docs/plugins/transform-object-rest-spread/). – Mac Cowell Apr 10 '17 at 07:51

2 Answers2

26

This helps make your code more succinct - since props is an object, the spread operator takes the properties of the object you pass in and applied them to the component. So the Component will have properties a foo with a value of x and a bar with a value of y.

It would be the same as:

var component = <Component foo={props.foo} bar={props.bar} />;

just shorter

pherris
  • 17,195
  • 8
  • 42
  • 58
9

One of the best overviews of how object-rest-spread syntax works with react is published at reactpatterns.com:

JSX spread attributes

Spread Attributes is a JSX feature. It's syntactic sugar for passing all of an object's properties as JSX attributes.

These two examples are equivalent.

// props written as attributes
<main className="main" role="main">{children}</main>

// props "spread" from object
<main {...{className: "main", role: "main", children}} />

Use this to forward props to underlying components.

const FancyDiv = props =>
  <div className="fancy" {...props} />

Now, I can expect FancyDiv to add the attributes it's concerned with as well as those it's not.

<FancyDiv data-id="my-fancy-div">So Fancy</FancyDiv>

// output: <div className="fancy" data-id="my-fancy-div">So Fancy</div>

Keep in mind that order matters. If props.className is defined, it'll clobber the className defined by FancyDiv

<FancyDiv className="my-fancy-div" />

// output: <div className="my-fancy-div"></div>

We can make FancyDivs className always "win" by placing it after the spread props ({...props}).

// my `className` clobbers your `className`
const FancyDiv = props =>
  <div {...props} className="fancy" />

You should handle these types of props gracefully. In this case, I'll merge the author's props.className with the className needed to style my component.

const FancyDiv = ({ className, ...props }) =>
  <div
    className={["fancy", className].join(' ')}
    {...props}
  />

-- quoted from reactpatterns.com by @chantastic


Another good overview was published on the babeljs blog post React on ES6+ by Steven Luscher:

Destructuring & spread attributes

Often when composing components, we might want to pass down most of a parent component’s props to a child component, but not all of them. In combining ES6+ destructuring with JSX spread attributes, this becomes possible without ceremony:

class AutoloadingPostsGrid extends React.Component {
  render() {
    const {
      className,
      ...others  // contains all properties of this.props except for className
    } = this.props;
    return (
      <div className={className}>
        <PostsGrid {...others} />
        <button onClick={this.handleLoadMoreClick}>Load more</button>
      </div>
    );
  }
}

-- quoted from "BabelJS.org blog - React on ES6+" by Steven Luscher

Community
  • 1
  • 1
Mac Cowell
  • 256
  • 2
  • 5