By Ian McNally
My friends started using it, Stride clients started asking for it, and it’s been getting serious buzz on the Internet. So I realized it was time for me to learn React.
I’ve been an Angular guy for the past couple of years, and I’ve gotten pretty good at it. I’ve seen its nooks and crannies, and I’ve grown fond of it.
But, like I said, it was hard to ignore React.
It’s fast, it’s light, it’s new and shiny. So I dug in. I recently released an app, Farely, which I’d written in Angular. (Note: I didn’t use directives as I should have.) I thought it’d be the perfect opportunity to try out React, since the app could be composed of components. It also wouldn’t need anything React doesn’t offer, like routing or complex data modeling.
And so I began the project. Below are my thoughts and observations, should they help inform your library choices. I’ll assume you’ve been introduced to React and Angular, since there are great articles written about them elsewhere.
Angular and CoffeeScript were my go-tos. React doesn’t play well with CoffeeScript, so I decided to write it in ES6. Why not lean into the future? Accordingly, some of my points in this post will deal ES6 and not necessarily React.
To handle transpiling ES6 to ES5, I used 6to5, now known as Babel. Finally, to handle module loading, I used Browserify. I’m really digging the import statements in ES6. Also, having all the source code build to one file, with all dependencies, means I can have a lean index.html with async and defer tags.
Thoughts and observations
I kept a pros and cons list while I was working. I resisted the urge to copy and paste that, or resort to a listicle. Instead, I’ve grouped my thoughts, below, into general areas.
After watching some tutorials online, I was concerned that React forced you into <div> soup, since you can only return a single element from a render function. The markup in the Angular Farely looked like:
So, I already had my containers. Breaking them up into components was easy:
Turns out I was worrying for nothing. Still, I do feel a disconnect between the actual HTML that’s rendered and what I’m writing in JSX. All rendered elements contain data-reactid. It does get easier to visualize with React Developer Tools.
While we’re on the topic of JSX, I’ll say that I was thrown off with the nonstandard attributes. For instance, this HTML—
in JSX looks like—
It’s something I got used to, but as I mentioned, it contributes to a feeling of distance between the markup and rendered HTML.
Also, I miss Angular’s form validation.
HTML + JS
Continuing on the subject of markup, I like that a React component has the code and markup in one place. Angular separates templates into their own files, which are referenced in code. Optionally, it allows for HTML strings. Other frameworks like Ember and Backbone support either strings or separate template files, often with their own syntax on top of it (I’m looking at you, Handlebars and Mustache).
Since I’m using Browserify, I can make use of Node built-ins, like Event Emitter, and Node modules. Also, I can use import/require instead of homemade dependency injection like Angular has. With ES6, I wrote classes. I used events.
I enjoyed not having to attach things to $scope, or return functions that returned functions that did something, or list my dependencies in any other place besides package.json.
Angular also has a tendency to do things its own way, such as changing the context of a function that was referenced in a template. It has its own lifecycle, too, which sometimes needs encouragement (see: $scope.$apply, $scope.$digest, $timeout).
Boilerplate code and manual binding
While Angular’s two-way data binding can cause some headaches (see lifecycle comments above), man, it makes things easy. Models change automatically, from either direction. It takes care of empty values for you, as well as exposing some common functions, such as checking whether something is defined. In React, you manually set states with handlers. I spent the longest time coercing input value types, with React. It can feel regressive.
Another bit of manual work was putting together a lot of the boilerplate code. To better organize the app, I used Flux—the architectural pattern–cum–library. It requires the setup of actions, stores and a , all of which require some mental overhead and spread responsibility over several files and directories.
As with any new project, best practices are still being developed. That’s one of the harder things about transitioning right now. Angular and other frameworks are pretty well established. Even the API is changing!
While that will get ironed out in the future, the fact that React is just a piece of what you’d get in a framework (the V in MVC, as they like to say) leads developers to piece it together with other libraries. It’s a little like the Wild West right now, but I’ve seen it with Backbone, Ember, and…gasp…Angular.
I’ve long been a proponent of the web. It can be anywhere and everywhere; it has decades of history and a rich set of standards. I like that Angular is positioned to work with web components. There is also a library for automatic accessibility tagging. That’s not the message I get from React, between JSX and React Native.
Jasmine and Angular make a great team. You can inject dependencies in your test, mock them, or spy on them. Karma, the test runner, supports any browser, including PhantomJS for headless testing. With React and Flux, Jest is recommended. It’s Facebook’s layer on top of Jasmine. It uses a virtual DOM instead of a browser or PhantomJS. This can make debugging hard, but it does run on the command line, so it’s good for continuous integration. Interestingly, Jest mocks dependencies by default but allows you to easily override that.
Note: remember to put jest.dontMocks above imports/requires. That took me a few minutes of head banging to figure out.
- React has great warnings about usages, like when it told me I didn’t have to bind a function in a component.
- React supports server-side rendering out of the box. Huge!
- I’m excited to see what React Native brings.
- You can require('React') and require('react'), which probably shouldn’t be possible. You’ll receive the cryptic error “Cannot read property 'firstChild' of undefined.”
So did I like React? Am I ditching Angular for it? Forgetting React altogether?
As you can expect, the answer is more nuanced than a yes or no. I found that I like React, especially once I got over the cognitive dissonance relating to JSX and the new jargon. What React does—components, fast DOM updating, controlling data flow—makes it a great tool. What it doesn’t do so well—routing, data modeling, etc.—means that it won’t necessarily replace your framework of choice any time soon. Still, I’m going to keep my eye on it, and keep working with it. It’s fun to use and has a lot of potential.