GregS GregS -4 years ago 67
Javascript Question

Undocumented method of passing element children: as attributes instead of explicit children

I have encountered some example JSX code in a book which took me by surprise - it contains an anchor tag in the single (non-closed) form. I have simplified the code:

function CustomAnchor(props) {
return <a {...props}/>;
};

ReactDOM.render(
<CustomAnchor href="http://reactjs.com">A link</CustomAnchor>,
document.getElementById('container')
);


The code works, but I haven't been able to find any documentation that describes this way of describing the anchor tag in JSX. I expected to have to use an opening & closing A tag, enclosing props.children - i.e - something like this:

return <a {...props}>{props.children}</a>


The latter form is in fact how it was done a bit earlier in this same book, and no explanation has been given on the new more condensed form. FWIW, the book is "React Up & Running", by Stoyan Stefanov. I'd appreciate some help here before I consider submitting a suggestion to add an explanation to the book.

Codepen: https://codepen.io/anon/pen/EmeOxW?editors=0010

Answer Source

JSX and React.createElement()

If you look at the Babel Compiler, you'll see that this JSX:

function CustomAnchor() {
  return <a {...props} />;
}

compiles into:

function CustomAnchor() {
  return React.createElement("a", props);
}

The createElement() function has the following syntax, as per the official documentation:

createElement():

React.createElement(
  type,
  [props],
  [...children]
)

So your observation makes sense! One would think that since the 3rd parameter is omitted then there shouldn't be any children.


Explanation

So what's going on? One would need to take a closer look at the source code to understand what's going on:

In ReactElement.js on line 170 in the react library:

ReactElement.createElement = function (type, config, children) {
  var propName;

  // Reserved names are extracted
  var props = {};

  ........

  for (propName in config) {
    if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
      props[propName] = config[propName];
    }
  }
}

For each value in the config object (i.e the 2nd function argument!), we pass it to props with the propName key. However, remember that you deconstructed props in your <a> element.

In other words, this:

<a {...props} />

is equal to:

<a href="http://reactjs.com" children="A link" />

This means that props object gets both an href and a children property, which is why you get the result you observed.


Summary

So in summary, this:

<Foo children="Bar" />

is equal to:

<Foo>Bar</Foo>

Opinion:

That being said, I would rather see the author use your suggested syntax and not the way he/she did it. One would expect educational material to be more clear and precise.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download