No-code React primer, including ES6, Babel & webpack
This is a very simple introduction to the concepts of React, in the context of Flux and Redux, and a brief mention of ES6, Babel and webpack, which are starting to be used regularly in React projects.
The intention of this post is to give someone without any prior experience of the above technologies a simple grounding in what they are and some simple reasons to use them.
A follow-up article, which walks through the creation of a simple React app/widget from scratch, can be found here.
What is React?
React can be thought of as the ‘V’ in MVC. It’s a view rendering framework that uses components (normally written using JSX) to render data to HTML. One of its biggest selling points is the use of a virtual DOM to speed up front-end responsiveness by ensuring that the fewest possible changes are persisted to the browser’s renderer when the display needs updating.
- It makes sense to keep the view’s layout and logic (user interaction handling) in a single file, as they are inextricably linked
- If you’re going to keep the presentation information in the code, then why not keep it as simple as possible? It’s possible to define an HTML tree in many ways (JSON, for example), but by far the simplest is to simply use HTML which is both familiar and explicit.
What’s the virtual DOM?
A tree of components in React can be rendered on either the client or the server (and indeed isomorphic applications can be created easily using React). Once that tree has been rendered in the browser and—when the data changes, requiring a UI update—the changes are made in a virtual representation of the DOM and a diff is executed against the previously rendered DOM to see what changes are required, with only these changes then persisted to the browser’s renderer.
This diff-and-patch technique is far faster and less intensive than passing the entire new DOM to the browser, and so improves performance of the front-end considerably.
Flux and one-way binding
React is just the view, and while it can potentially be paired with any framework, its default partner is Flux, Facebook’s own application architecture. In their own words:
“Flux is the application architecture that Facebook uses for building client-side web applications. It complements React’s composable view components by utilizing a unidirectional data flow.”
Rather than using the previously popular bidirectional binding that tightly synchronises the view and the model, React apps use one-way binding that always reflects the model in the view. Changes to the view are handled by listening to events, and using these to directly or indirectly update the model(s).
The advantage of doing it this way is a much greater simplification of the binding logic, and the removal of many ways of self-sabotaging the application by getting into messy feedback loops.
How it works
Every modification to the UI begins with an action, fed through the dispatcher (which enforces one-action-at-a-time), which then updates the store(s), and ultimately the view(s). If the view requires further changes to the model because of the new state, it will then fire an additional action to effect this.
Here’s the original Facebook video that describes Flux in further detail, if interested (well worth a watch).
Redux is a version/implementation of Flux that tweaks the concepts slightly. Instead of multiple stores and a dispatcher to enforce single-action-at-a-time, Redux uses a single store and the use of pure reducer functions to modify the store.
The actions are now objects that describe what happened (often just a string ID and extra contextual information), which the reducer functions use to determine how to modify the store.
A reducer-function is a function with the signature f(a, b) = a where the contextual information b is applied to the original object a and returns a new version of a. The most common usage is in Array.prototype.reduce()
Once the store has been updated, React will then update the view accordingly.
In order to work out when the state of an application has changed, you normally have to diff the new and old state. If, however, that state is stored as an immutable object, then we can tell whether it’s changed with a simple equality comparison. The speed differences are obvious.
In practice, this means that the reducer functions used to handle the actions and update the state-model should not mutate the existing model, but should rather replace it with an updated one.
One of the benefits of doing this is that undo/redo functionality is almost baked-in, and in fact Redux can very easily support this feature. Because the current state is simply a starting state and a sequence of actions, transitioning along this state-timeline is a relatively simple affair. When have you previously ever heard “simple” and “undo/redo” used together when describing a web-app?
While certainly not mandatory, React and Redux examples are commonly written in ES6 (which is actually called ES2015, but seems still to be known more by its earlier name). The advantages are more concise code, taking early advantage of newer language features, and an ever expanding collection of examples to “take inspiration from” in the React/Redux ecosystem.
The use of Babel means that this can be used right now, and indeed you can even use features from ES7/ES2016 in your code, knowing that it will all be transpiled down into ES5 to run in almost all modern browsers.
Tying everything together, webpack uses Babel to consolidate all of the code (including the JSX) and combine it all into a single file, for optimal HTTP1.1 efficiency.
Coming from a Grunt background (and not even having made the jump to Gulp yet, because of a general preference for configuration over coding), why would one need another build system? Here’s a great article on that subject, but essentially it’s because it’s more opinionated … if you buy into the way it does things, you’ll have much less work to do for the same result, and who doesn’t want that?
The big appeal for using this “ecosystem” for development of applications is in what you give up. You don’t have to worry about changing the DOM. You don’t have to care about how your UI needs to transition from one state to another … you just define how it looks in each state. It’s much more of a declarative approach to building websites, and it makes the developer’s life so much easier.
The benefits of doing it in this way are a simplification of the internal logic and the resultant improvements in quality (and performance), which is a boon for both the developer(s) and the client.