JSX Looks Like An Abomination
But it’s Good for You
JSX is like a healthy vegetable that tastes like decadent chocolate cake. You feel guilty, but it’s good for you. (Tweet this).
What is JSX?
JSX expressions evaluate to ReactElements. Think of them as shorthand for calling `React.createElement()`.
Here’s a sample JSX expression for an editable email field:
Let’s break this down:
There’s a set of event handlers that you hook up in a way that should look very familiar to anybody who knows HTML.
… and that’s where many developers tune out. At first glance, this looks like the unholy love child of 1990's DHTML and 2015 ES6. We’re talking some Frankenstein madness… right?
Well, not quite. Let’s take a closer look.
JSX is Not an HTML Template Language
Though it looks like it, JSX isn’t a template in the sense that Handlebars and EJS are templates. It’s not a simple token replace and `.innerHTML= foo` dump like so many other tools.
It’s actually a declarative syntax that’s used to express the virtual DOM. JSX gets interpreted and converted to virtual DOM, which gets diffed against the real DOM. Rather than rewrite the whole DOM tree, only the differences get applied. That makes React renders fast.
Additionally, JSX builds in common protections against XSS attacks.
JSX is not limited to HTML. You can use it to create arbitrary object trees. Netflix uses that capability to mirror their web app architecture on a wide variety of devices using their own custom object model for TV rendering.
React Native uses it to render device-native UI elements.
In this sense, JSX is actually a lot more flexible and versatile than a Handlebars template can be.
JSX Event Handlers are NOT Like HTML `onClick`
Despite using the familiar attribute syntax, JSX doesn’t handle events like the same syntax in HTML would.
JSX events get automatically delegated to the root React node. Actually, it goes a step further. It sets up a single event handler on the root node that handles all your events.
What does that mean? Normally when you attach event listeners directly to the element that the user interacts with, you end up with potentially many event listeners in memory for a single page. React creates a single listener automatically, so you never have to think about event delegation again.
This is really great for things like infinite scrolling, because you don’t have to worry about infinitely growing memory consumption (memory leaks).
It looks like DHTML from the 90's, but under the hood, it does the right thing.
Designers Don’t Mind JSX
At first glance, I worried that designers would be scared off by JSX, but I’ve discussed this concern with lots of teams using JSX, and the design teams adjust quickly, and frequently find it easier than working with HTML templates and CSS, which brings up another point…
Inline Styles Are Good
I struggled with this at first. I was all-in on the idea of CSS, but in practice, CSS has failed in a lot of ways. First, it’s essentially a global playground, and CSS selections often overlap in undesirable ways and create awkward side-effects, which leads you to get more specific with the selector, which in turn makes your CSS selections more brittle, so they break when the DOM changes.
Putting styles in a React component is more akin to putting styles in a web component than putting styles into raw HTML. If you did it in raw HTML and you wanted to change the look of a buy button, and you have 10k items, you’d need to update the style in 10k places.
Components don’t work that way. Since the style is in the reusable component, you only have to update it in one place, and you don’t have to worry about selector scoping.
As a bonus, you also get style variables, style modules, style inheritance, and a number of other things you’re already using a preprocessor for — but now you don’t have to learn a whole new syntax. You do it in JS.
I thought I’d hate it, but I love it.
(The Right) Separation of Concerns
React is all about separation of concerns. That may sound surprising coming from a guy who wrote in detail about why business logic and data management should be separated from presentation — but if you’re using React correctly, the only concern you should be worried about is presentation.
React doesn’t deal with data or business modeling. All it does is render stuff efficiently and delegate events. It knows the data it needs to render, it knows when to render it (when the data changes), and it knows how to render it efficiently. Similarly, it knows how to relay UI intentions back to the application.
What it doesn’t know is anything about what the application is doing with those user intentions, or what any of the data means to the business model or business rules.
If you’re putting business rules
in React components,
you’re doing it wrong.
I hid some things from you earlier. Let’s look at the complete component from above. This is a simple reusable component that displays an email address. When you click on the email address it switches to edit mode, which swaps the displayed email out for an HTML5 email input:
Notice there is no state anywhere in this file. The component doesn’t even know whether or not it’s using edit mode until you tell it with `props`. This is a stateless component.
Stateful components are an
anti-pattern in React.
Update: Anti-Pattern, Really?
Sometimes, but rarely, it can be useful for a component to maintain internal state. As Rich Hickey put it:
“If a tree falls in the woods, does it make a sound? If a pure function mutates data to produce an immutable value, is that ok?” ~ @richhickey
In other words, as long as your state isn’t causing side-effects, maybe it’s OK. Still confused? I made you a flowchart.
One big exception to the state rule-of-thumb is container components. I use container components to integrate generic, reusable UI components into the specific state context of the application.
What are `props`?
They’re the data that get passed into the component as element attributes. Somewhere else in the app, React listens for state changes and the `render()` method gets called again passing the changed data into the `props`.
You might also notice that the component doesn’t have any notion of what the event listeners are doing. I used a trick here that makes the component really easy to test and reuse in any app — I wrapped it in a factory function.
The factory allows you to pass in all the dependencies, including React. You could even pass in base styles if you wanted to, so your component can inherit standard styles from the rest of the app. In this case, I didn’t do that, but did pass in `setEmail()` and `setEditMode()` functions. In React / Flux lingo, those functions are called actions.
Actions communicate the user intentions to the app. This component doesn’t know anything about how your app listens for or responds to actions. It doesn’t know anything about how you store and manage state. All it knows is how to trigger those actions in order to communicate user intent.
It’s up to the app to take over from there.
with Node, ES6 & React.
He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.