Object Spread and JSX explained

Every respectable front end developer has now, at the very least, heard of React and for good reason. React brings some amazing enhancements to front end development. After hearing about these enhancements for months, I finally made the plunge into making my first react app.

I decided, that for my first project I would make a simple recipe box app. This would allow me to get my hands dirty with all the CRUD operations while still making sure I don’t get in over my head. While going through this project I came across this cool little thing you can do…

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

On first glance you may think “that’s pretty cool”. But lets backup for a second and appreciate how huge this is with an example from my recipe app. Before using Object Spread I had…

const recipes = this.state.recipes.map(recipe => {
return (
<Recipe title={recipe.title}
key={recipe.title}
ingredients={recipe.ingredients}
instructions={recipe.instructions} />
);
});

after Object Spread…

const recipes = this.state.recipes.map(recipe => 
<Recipe key={recipe.title} {...recipe} />);

I’m going to use this right now!!!

There are a couple of problems here. First off Object Spread is not even a standard yet.

It currently exists as a stage 3 proposal which means, that while it is likely to be adopted at some point, it currently is not and we don’t know at which point it will be. This may scare you at first but keep in mind though that Babel, the most popular transformation library currently supports Object spread. See http://babeljs.io/docs/plugins/transform-object-rest-spread/. In addition most — if not all — are using JSX to write react. This means that our code is going through a transformation step through reacts compiler (this is also done through babel). In addition as noted in the redux documentation

this is still an experimental language feature proposal so it may change in the future. Nevertheless some large projects such as React Native already use it extensively so it is safe to say that there will be a good automated migration path if it changes.

So regardless of it’s progress in becoming standardized we can feel safe in using this great feature knowing that we are in good company.

But how does this all work?

This just leaves one problem, according to the proposal

where z = {
a: 3,
b: 4
};
let n = { x, y, ...z };
n; // { x: 1, y: 2, a: 3, b: 4 }

so how on my great grandmothers grave does

{...recipe}

become

title={recipe.title}
ingredients={recipe.ingredients}
instructions={recipe.instructions}

To answer that question we have to take a look at how JSX gets transformed to make html elements.

JSX Transformations

To explain JSX transformations I’m going to use my recipe box example. If you would like to view the source it can be found on my repo at https://github.com/haasDev/recipe-app. In my app the simplest component is found in Ingredient.jsx which looks like this.

export default ({name}) => (<div>{name}</div>);

and in the dom it is rendered as

<div>Ingredient name</div>

So how does this happen? The answer is that react converts it to a function called createElement. createElement has 3 parameters. The first is the name of the dom element you would like to create, the second is an object containing any props you are passing to another element — we’ll see an example of this later, the third is a string value containing the text between the angle brackets. So in our example we would get:

React.createElement(div, null, "Ingredient name");

Simple enough, but what about a more complex element? Lets go one layer up in my app and we can see this. In Recipe.jsx I am using react-bootstrap to handle some of the styling for me. In this example we are using the ListGroupItem component to wrap my Ingredient component.

<ListGroupItem key={ingredient}>
<Ingredient name={ingredient} />
</ListGroupItem>
Which would be converted to:
React.createElement(
ListGroupItem,
{key: "ingredient name"},
React.createElement(
Ingredient,
{name: "ingredient name"}
)
);

Object spread and React

I hope by now its a little bit clearer why an object that looks like {title: recipe.title} can still work the same as title={recipe.title}. Normally react looks for some word followed by an equals sign and converts that to a key value pair to pass as the second argument in createElement. The great thing about the object spread syntax is not only is it a lot less code to type but it also is a little less work for the compiler todo since we are already giving it an object which is its desired target format!

There it is, you now understand how the object spread operator works within react and can now go about using all the greatness and power it provides. If you have any questions feel free to reach out. You can find me @haasdev on twitter or by posting a comment here. Hope to hear from you soon!

Show your support

Clapping shows how much you appreciated Tyler Haas’s story.