How I learned to like JSX and moved on
Okay, so there’s this thing called React. Depending on who you ask the question, it’s either a framework, a jQuery replacement, a magic unicorn or a library for building user interfaces. I won’t get into detail about what it actually does, but it’s worth mentioning that its key feature is actually doing as little as possible at a given time. That’s what makes it fast, since the DOM is slow, yadda yadda yadda.
Here’s a snippet you’re highly likely to encounter when approaching React for the very first time:
ReactDOM.render( React.createElement('h1', null, 'Hello, world!'), document.querySelector('#foo') );
Looks pretty self-explanatory so far (except for the ‘null’ part maybe). But then, there’s this:
ReactDOM.render( <h1>Hello, world!</h1>, document.querySelector('#foo') );
The weird syntax above is JSX and my first thought about it was “Why do these HTML strings appear without quotes?” Below is a list of my original concerns regarding JSX along with a few words on how they evolved over time.
The syntax
Back then:
A mixture of JavaScript and XML in one file felt intimidating for a few reasons. First of all, it’s neither valid JavaScript nor like any of the compile-to-js languages I’ve seen before. I was wondering if my code editor of choice would manage to highlight JSX in a reasonable manner (and of course, it didn’t). I was also concerned if a syntax managing to look strangely unfamiliar in a 3-line code snippet manages to scale in a large project. A potential 500 LOC multi-syntax soup is what I was discouraged by most. Another thing came directly from my previous experience with Angular: some attributes being quoted and some not didn’t seem appealing. All this made me use React APIs (e.g. React.createElement
) directly, wherever I could.
Today:
You never really get to know a tool unless you spend a reasonable amount of time playing with it. My original fear of making the code unreadable actually came true but not as a result of the JSX itself. Throwing a bunch of React.createElement
calls along with nested tree structures (the last argument is where you pass child elements) turned out to be a clear path to having a dense wall of code. React’s built-in factories (e.g. React.DOM.div
) don’t really make any significant difference here. After my eyes stopped bleeding, I really started to see the benefits of the quasi-literal syntax for creating React elements. In fact, the only thing the JSX transformer actually does is replacing those with appropriate React API calls. Whereas transforming JSX to JS for creating a single h1 seems like overkill, imagine how the actual JavaScript for creating a structure like the one below would look:
<div class="nav-docs-section"> <h3>Quick Start</h3> <ul> <li> <a href="/react/docs/getting-started.html" class="active">Getting Started</a> </li> <li> <a href="/react/docs/tutorial.html">Tutorial</a> </li> <li> <a href="/react/docs/thinking-in-react.html">Thinking in React</a> </li> </ul> </div>
There’s one caveat one needs to be aware of when using JSX syntax, and that is the automatic semicolon insertion.
In terms of syntax highlighting, babel-sublime does an excellent job (it’s easily installed via Package Control).
To address my last concern: what seemed to be JSX’s weakness turned out to be it’s strength. Consider this code snippet (taken from an AngularJS template):
<div data-prop="bar"></div>
The value of the data-foo attr can be either “bar” (string) or some bound value from its surrounding scope (or one of its parent scopes). We can’t really say what’s happening by just examining the template. Below is a JSX snippet:
<div data-prop="foo"></div> <div data-prop={this.props.foo}></div>
It’s 100% clear here — quoted values are interpreted verbatim, those in curly braces stand for data bindings.
Separation of concerns
Back then:
I didn’t like having markup inside my JavaScript. It seemed nearly as bad as having CSS there as well. I grew up in a culture where you keep your templates separate (whether they are or aren’t preprocessed at some later point). Also handling events via on* attrs seemed very medieval.
Today:
The thing with JSX is that it’s not a templating engine in a strict sense of the word. I’d rather call it a template engine () for generating templates (React.DOM.div
) which are not in fact templates, but… never mind. To name one difference, React only renders attributes it supports to the DOM, all others are treated differently (take props) and only used for React-specific puropses like passing data/state down the tree of components or binding (synthetic) event handlers. JSX also allows for embedding raw javascript (inside curly braces). All this makes it very convenient to have the “template” right next to the place where all the component logic resides. In terms of event binding – on* attributes are just a syntax sugar (React handles all events via delegation) and are not reflected in the actual DOM.
Bloat
Back then:
It might seem that JSX encourages creation of components bloated with hundreds of lines of it’s html-ish thing. And that’s indeed how the very first React components I built with it looked. At that point I really wanted to keep the template part of my components separate.
Today:
One of the best things about React is that components can be composed of other components. Components can also be wrapped in higher-order components for creating factories tailored specifically for your needs. If you apply a single responsibility rule on top of it, you’ll get React components encapsulating small, self contained pieces of the UI and parent components for utility functions like grouping child components or keeping track of the application state. At the end of the day, your components will mostly contain a minimal amount of “html” (actually, JSX). Consider the example below:
<div className="person"> <Avatar {...this.props} /> <ProfileLink {...this.props} /> </div>
Adds to development/build complexity
Back then:
Since JSX requires being compiled to JS before it can be consumed, there’s a need to employ another third-party tool to do the compilation for us. It requires tweaking both our build scripts and development servers (compile on every cmd + s) to perform an additional step. It also introduces one more level for generating sourcemaps (yep, sourcemaps are a must when working with JSX).
Today:
The truth is that these days a typical development setup based on either grunt, gulp or webpack for working with either of the popular JavaScript frameworks is the size of the first Linux distribution. To name a few examples:
5 years ago, this would probably matter, but things have changed. In my case (I’m using gulp along with browserify + babelify) all changes boiled down to:
- installing & adding ‘react’ to babel presets
- …
- wait, that’s it
whoah this weblog is great i love reading your posts.
Stay up the great work! You realize, a lot of individuals are
looking round for this information, you could help them
greatly.