Why React?
React is an outstanding compromise between pure, functional, declarative principals and the loose, dynamic reality we work within. It allows developers to write interfaces in a component-driven way that describes the result of a render based on the current properties and state at the moment. Behind the scenes, it uses an efficient diffing algorithm to keep your UI up to date using the minimum number of manipulations possible.
Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
React - Components and Props
With React, you can gradually transition your application from prototype to production, adding strictness as you're ready for it with tools like TypeScript and unit testing. You can use it as a universal pattern for crafting interfaces across diverse platforms, while maintaining a sound functional core that is shared between each application. Like any powerful tool, though, it's easy to misuse. With some planning and discipline, however, you can achieve a high level of stability while still keeping your code maintainable for those who come behind you.
A Brief History
On May 29, 2013, Facebook released the initial open source version of React. It was created by Jordan Walke and inspired by Facebook's XHP project, which was itself inspired by another project called E4X. These libraries both allowed you to easily embed XML in other languages, which led to the creation of JSX—an extension of JavaScript syntax that allows easy embedding of XML/HTML.
This may be the single most controversial aspect of React. Writing HTML in the middle of your JavaScript files initially felt like a return to the jumbled days of inline PHP. I was personally very critical of React for it in the beginning. Today, however, I hold JSX in very high regard as a great way to dynamically express composable elements of a user interface so that they are easy to visually scan and understand. It's what makes React's elements on the web and in native platforms so easy to take in at a glance.
Some time after Instagram joined the Facebook family, Pete Hunt was introduced to React and wanted to use it for Instagram. He worked with others at Facebook to refactor it into an open source package to give back to the community. It was initially received with some confusion and skepticism. In addition to protests about separation of concerns in JSX, there were also loud critics comparing React to Angular and Ember and pointing out the lack of two-way binding, and criticizing Facebook's unorthodox "virtual DOM" approach to managing DOM updates.
The virtual DOM is a programming concept where an ideal, or “virtual”, representation of a UI is kept in memory and synced with the “real” DOM. [...] This abstracts out the attribute manipulation, event handling, and manual DOM updating.
React - Virtual DOM and Internals
Facebook's Bill Fisher stepped in to clarify their approach to one-way data flow by open sourcing Flux, an architectural pattern for reactive interfaces built around what was essentially an event loop. Stores formed the single source of truth for the interface, and DOM events ended up dispatching actions to the stores to update them. When stores were updated, React components were re-rendered based on the new state. In typical front-end MVC frameworks of the day this approach would be far too inefficient to be viable. The virtual DOM makes this possible by automatically managing DOM manipulation and only updating elements when they change.
Despite the prominence that the virtual DOM enjoys today, the team's initial focus was on JSX and reusable components. The virtual DOM was a way to make it perform well enough to be practical. The result is an efficient system for managing rendering in a predictable and maintainable way.
Managing Mischief
That's all well and good, but when it comes down to it why would you choose React rather than one of the infinite alternatives out there on npm? The bottom line is that the front end - regardless of whether that front end is an HTML/CSS/JS document rendered in a web browser or a native mobile view rendered in the React Native runtime - is a chaotic asynchronous event-based system that runs in tightly constrained execution environments. It is often error-prone and difficult to debug.
React introduces a declarative, functional interface that makes it easier to manage rendering in a maintainable way. To achieve this, it uses a diffing algorithm against an in-memory intermediate representation of your interface to make the minimal set of UI changes necessary for each render. This cuts down on the work that the browser or React Native runtime needs to do to keep your UI up to date as things change.
A declarative language abstracts away procedural details, instead focusing on the form of the result.
Composing Programs 4.3 - Declarative Programming
Though the ability to combine HTML, CSS, and JavaScript all in one file initially seems contrary to traditional best practices - it enables rich, expressive interfaces that are automatically bundled into the traditionally separated layers for efficient usage by the browser.
With these tools, you're able to build encapsulated components that make it easy to reuse logic and write comprehensive unit tests around what matters. You can organize your interface into single units of functionality and/or style, composing them together into rich interfaces formed from reusable building blocks.
Encapsulation refers to the idea that objects should manage their own behavior and state, so that their collaborators need not concern themselves with the object’s inner workings.
Deviq - Encapsulation
The ability to render not just to DOM and the browser, but to render to other platforms like native iOS and Android views is a very powerful abstraction that allows you to use the multitude of tools available on npm to build easily maintainable mobile applications without having to know a large amount of platform-specific code.
The ability to share a core set of logic across those platforms is the killer feature that makes React the absolute best way, in my opinion, to write cross-platform applications in a fraction of the time that it would normally take.
Gradually Functional
React enables functional programming patterns in a way that can be applied gradually, enforcing strictness and purity where needed and allowing looser implementations for prototyping or pre-release code. It doesn't enforce purity or prevent an object-oriented approach, but it gives you a great set of tools to describe your interface purely given the current state at any point in time and keep it up to date efficiently.
To take full advantage of this, however, it's necessary to use React with restraint and discipline. As with much of the JavaScript ecosystem, you get plenty of ammunition to shoot yourself in the foot with. To prevent unpredictable errors but still keep your code easy to maintain over time, a good strategy is to keep a strict, functional core of business logic and API interactions, wrapped in a dynamic shell of presentation and markup.
If your state management and actions, API clients, and core logic are kept as strict and functionally pure as is practical, then it's relatively easy to wrap and re-wrap them in presentational views for different contexts or even different device platforms.
React's flexible nature also allows for quick iteration and prototyping at first, while gradually embracing more sound code as you approach production. In well-crafted design systems built with React, designers can often come in and use a set of composable React building blocks to mockup interfaces in real code with no need to dip into the HTML or CSS.
Though I love purity and sound functional programming, I've found the flexibility of React to be ideal for building real-world interfaces in a practical and iterative way. Combined with tools like TypeScript, especially, it can still provide a platform for tight correctness while still being usable in a tight-deadline environment. ⚛︎