Blog of Raivo Laanemets

Software development and personal stories.

Feeds app rewrite in React

On 2017-07-03

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.