Why we chose React
During my time at Green13 Solutions I have been responsible for creating our bespoke browser-based interface for developing actuarial models.
I was recently explaining to a client why I chose React to build our UI and, in particular, why we moved away from AngularJS (v1.x) to create this new suite of tools.
Here is a summary of they key reasons that helped me reach this conclusion.
TL;DR
React provides a great set of tools that make it easy to manage complex data-driven web applications. I have really enjoyed working with the power and flexibility provided by React. I am happy with the decision I made and stand by my choice.
These are the main reasons that I favoured React:
Declarative — creating structure and layout of the UI and writing code to manage state across the app is handled automatically by React in a powerful way
Data model — React embraces uni-directional data flow (data moves from a parent to a child component) which makes data management logic transparent and predictable
Flexible — React easily integrates with wide variety of other technologies and stacks because it is manages the ‘View’ layer of an app
Powerful language tools — React embraces the best language features of modern JavaScript
Great community support — makes it easier to solve problems, great tooling and plugins
Declarative way of managing state
The main benefit of using a library/framework in the first place over ‘vanilla JavaScript’ is to make it easier to keep the UI in sync with the data model.
React abstracts away a lot of the complexity of managing state in JavaScript apps. This makes it practical and manageable to develop large applications.
An example of this is how we only have to call the ‘setState’ method in response to a user action (for example clicking a button) and React will automatically handle the challenges of propagating our intent and ‘reacting’ to these changes automatically across a whole complex hierarchy of components.
Declarative way of creating interfaces with JSX
Developers can chose to create the layout and structure of their user interfaces with JSX (why would anyone chose the alternative?), which is a JavaScript language extension that looks a bit like XML. Furthermore, developers can use JSX to write JavaScript code sitting alongside their markup.
I have found that having markup and logic contained in the same file makes it easier to manage files in the project hierarchy. This is in contrast to using other frameworks in the past where there were a multitude of HTML files and JavaScript files that all powered the same ‘unit’/‘component’.
Also, the project at hand was to create a really responsive and data-driven interface and for this reason it was natural to mentally model parts of the interface as a combination of JavaScript logic and markup. It was easy to think of data and markup as two sides of the same coin. So, to me, it feels completely natural to use JSX to nest JavaScript logic directly alongside markup for this type of application.
Unidirectional data flow
A React application is made up of lots of reusable components. These components are combined together to create rich interfaces.
With React, data can only flow from parent to child components.
A good analogy for this is an orange falling downwards from a tree. Imagine oranges are packages of data and branches are a React component. As the orange falls downwards it can only interact with branches below it … but not above it or to the side of it!
Child components can only trigger a change in part of the component hierarchy at a higher level through using ‘callback functions’ (the parent passes the child component a function as a parameter and effectively says ‘call this function and I will do something in response’).
Note: this is still unidirectional data flow, as the callback function is passed from parent to child and then any changes to data structures made in the parent component are passed down to child components in the usual way.
Lots of other frameworks offer various alternatives, for example ‘two-way binding’. Using this approach, when data is changed in the view it also updates the data in the model (held in the state of a component) and also the other way around. So, for example, typing into a text input box will automatically update the state of the application without the developer having to update the state explicitly.
The unidirectional data flow approach makes data manipulation and data sharing transparent and predictable. This approach made it a lot easier to scale our codebase and it has also saved countless hours in debugging.
Flexibility with other tech
React provides the ‘View’ layer for JavaScript applications. This means it isn’t like lots of other JavaScript libraries, in the sense that it doesn’t come included with lots of the tools needed to create a modern JavaScript application. For example, React doesn’t come pre-packaged with tools for central state management, routing and making HTTP requests.
There are obvious pros and cons to this. If I were making this decision working in a large organisation where there were lots of different teams working on web apps I would probably favour a framework like Angular because there is an opinionated and easily-available way of doing most fundamental things that a complex web app needs.
However, I was the core developer on the project and we wanted to do some interesting and sophisticated things with our interface, so I decided that the flexibility that React provides would allow me to select the best tools for our needs. For example, it has allowed me select Redux for central state management and Redux-Logic for asynchronous data-management middleware as opposed to the other options available.
Embraces OOP and FP … the best of both worlds
In the last few years JavaScript has matured significantly and has arguably embraced some of the best features of both object-oriented programming (OOP) and functional programming (FP) paradigms. For instance, developers now have a native concept of ‘classes’ in the language (even if they are just syntactic sugar on top of prototypal inheritance) and techniques like ‘mapping’ and ‘currying’ are commonly used.
I believe that React has embraced this ‘best of both worlds’ approach, to great effect.
OOP — Developers can use inheritance to extend the React Component class to create stateful components. These provide developers with a clear and powerful API to create their own functionality. For instance, they provide access to powerful methods for setting and managing state. Furthermore, the lifecycle methods provided by the Component class give developers an enormous amount of control and help reduce the development cost of using a JavaScript abstraction like React.
FP — A while ago React started supporting ‘pure’ components (also known as ‘functional’ components), which are ‘pure’ in the same sense as a pure function in functional programming (given the same input will always produce the same output). Pure components are useful because they reduce boilerplate code and make it easy to create unit tests for your UI, something that hasn’t always been easy in the past.
Community Support
Another big advantage that React has compared to other frameworks is the support, documentation and help available online. The fact that it is so popular means that there is a large amount of resources to help when you get stuck.
There is really rich ecosystem of support and development tools that make creating and releasing React projects a lot easier. Also, there are lots of open source components that are developed and maintained by a large community, so you can choose from a wide range of options for things like pickers, charts, and buttons.
Reflection
The project has been in production for several years and I am the owner of this piece our stack.
I really like working with React. It provides a great balance of a powerful abstraction for things like the managing complexities of state-management while also being transparent and easy to scale.
There are some downsides to using React that I have experienced (for example it can be a challenge to find the most appropriate library for a plugin) but despite these I am happy with the architectural decision I made and I stand by it.
Thanks for reading! I hope you found this useful. Please feel free to add any questions or comments below.