Feeds app rewrite in React
On the last weekend I rewrote my Feeds app (live) UI in React. I originally wrote the application many years ago and used KnockoutJS back then. This rewrite gave me some useful insight about writing a Single Page Application in React and gave me a chance to compare it to KnockoutJS.
KnockoutJS
KnockoutJS is a two-way binding MVVM library based on implicitly tracked observables. By the time of writing the original application code, it was targeting pre-ES5 JavaScript (IE6 support!) and did not have components support built-in. The application code was structured around a god object which kept the whole state and a set of templates that were rendered depending on the requested view (articles, feeds, feed articles etc.). This made the code relatively compact but also made adding new functionality harder than it should be.
KnockoutJS templates are based on DOM. Template binding is achieved by using special data-bind
attributes. The binding syntax is
similar to JavaScript. The syntax can be arbitrarily extended and cannot be linted.
React
React is also a view library but it uses different concepts than KnockoutJS. It does not use two-way binding. Input from the page DOM is "read" using events. There are no observable properties, state changes are detected by comparing immutable state objects. The code is structured around components where state changes are applied through the special setState method. Inter-component communication is handled through props (from parent to children) and events (from children to parent and from DOM to component).
React uses JSX (JavaScript Syntax eXtension?) to generate DOM. JSX is an XML-like language, designed to be embedded into JavaScript. It is compiled into JavaScript. Compared to KnockoutJS binding syntax, JSX has strict specification, is lintable, supported by IDEs/text editors, and has multiple alternative implementations besides React.
JSX requires a compilation step. In the React version of the Feeds application this is handled by Babel. In fact, this is the only transformation that I have enabled in Babel. With this application I only target evergreen browsers, all of which support enough ES6+ at the moment (I do use CommonJS modules with Webpack, not ES6 modules). JSX was the reason why I did not consider using React before. In 2013, when React was first released, JSX tooling was garbage. This has completely changed for now.
State management
A big topic about React is state management. The use of immutable data requires a specific approach. There are libraries for simplifying it, such as Flux and Redux.
The Feeds application does not have much global state (only the authenticated
flag is global) and I did not use a state management
library. Instead, I used the Container Components pattern
where the application state resides in a few selected components and is loaded over AJAX. Example:
ArticleList is a
container component for a set of
Articles.
Issues
The only issue I encountered during the rewrite was inconsistent charSet
attribute on the meta
tag. For some reason React
did not warn me about the invalid attribute and chose to just not render it.
Feelings
I think that React has come a long way and I plan to use it in my new applications. I'm also experimenting with JSX on the server side where it provides much better abstractions than string-based templating languages such as EJS. A couple of months ago I wrote a proprietary Electron app with Vue.js, another popular view library. While Vue.js is closer to KnockoutJS (DOM templates, two-way data binding), there is something in React (maybe it's the use of immutable data structures, the simplicity of pure components, and JSX) that makes me more and more sympathetic towards it.