Power of Eloquence

When saying “Hello World!” isn’t enough anymore

Working With States in ReactJS - Understanding Why and How We Should Start Caring About Them

| Comments

Ever since Facebook officially made ReactJS library open-source for the global dev community back in 2013, there has been no slow-down with its meteoric rise as the next ‘best’ Javascript library that jQuery could never be (or never able to catch on).

It’s a pretty big bold statement for me to say this after reading this article online, explaining the design process of implementing ReactJS when building front-end applications, and comparing its main contrast to jQuery’s application-building approach. The author went on, highlighting the importance of maintaining the separation of concerns between states information and the actual DOM elements that rely on them; and making points on how jQuery may not handle this aspect of good software development practices very well and its other drawbacks.

After working within the front end(FE) space for some time, where the majority of my time was spent on hacking jQuery, the article casts some reflections on how using jQuery was (and still) a great multi-purpose utility tool for web developers for building web user interactivity for a very long time.

Before I start discussing on working with states in ReactJS, I must divert your attention to another important matter. This will shed some light on why (and how) we got more involved in dealing with states than it was originally intended in the first place.

The Good-Ole Days

Those were the days…

To give you a bit of history, traditionally, on the FE, Javascript/jQuery enables web developers to do everything from filtering table’s data, toggling menu navigation, form submissions, records pagination to image carousel plugins etc. Together, tying with back-end(BE) languages such as Perl, Ruby, PHP, Python etc, and databases like MySQL/MSSQL server, you can call yourself a pretty decent full-stack web developer back then. During this whole time, everyone was pretty much contented with it. There were our bread-and-butter of our core web development tools.

This was truly the case until…

Single page applicatios(SPAs) came along.

Typical SPA Architecture

Source taken from MSDN website: https://msdn.microsoft.com/en-us/magazine/dn463786.aspx)

SPAs’ presence came due to the increased demand from online users wanting to experience fast dynamically-generated websites or web apps like they do with their desktop applications. These same sites or apps are generated or fetched from a single page load request thus no successive page requests from a server are needed. Doing so will cause interruptions for user experience when, say, requesting for some pricing table information as they submit the form via a browser. Hence, a single page load means better user experiences and faster user feedback. All content is dynamically generated via AJAX and JSON(most, if not all of the time).

This is the core importance of SPA.

With this, that’s why the web community is completely “littered” with so many SPA frameworks to build rich interactive apps over the years. jQuery was caught right in the middle of that. The demand for UI experiences has organically grown more complicated, more diverse and, to a certain extent, more sophisticated over time. Richer UI experiences mean that a lot of that business logic and application logic have since shifted towards the FE; thus BE has lighter responsibilities than before. Ultimately, this means FE utilities such as jQuery (along with HTML and CSS3) is getting more serious in managing states for various parts of the application (as pictured above). However, as the author described, how web states can grow out of hand very quickly with jQuery with its spaghetti code, it will soon start to tire web developers in manipulating them around.

Look at all that jQuery spaghetti code you’re going to end with
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//Original source taken from  http://kstover.codes/the-amd-pattern-part-1/

(function($){
  $(document).ready(function(){

   $(.ninja-forms-input).bind(keypress, function(el){
      //some ugly magic code goes here
    });

   $(div.label-inside input, div.label-inside textarea).focus(function(){
     //some ugly magic code goes here
   })

    $(div.label-inside input, div.label-inside textarea).blur(function(){
      //some ugly magic code goes here
    })

   if($.fn.mask) {
      $(".ninja-forms.mask").each(function(){
          var mask = $(this).data(mask);
          mask = mask.toString();
          $(this).mask(mask);
      });

      $(.ninja-forms-date).mask(date-format-mask);
   }

  if($.fn.datepicker) {
    $(ninja-forms-datepicker).datepicker(some-date-picker-options);
    //put your spaghetti code here..!
  }

  if($.fn.autoNumeric) {
    $(ninja-forms-autonumeric).autoNumeric(some-auto-numeric-options);
    //put your spaghetti code here..!
  }

  });
})(jQuery)

When one problem surfaces, a new solution beckons - FE MVC frameworks.

Thus, Backbone/Ember/Knockout and Angular were born.

Happy Again

Happy times for jQuery devs!!!

Hah… I wish.

These frameworks/libraries were able to help alleviate the pain of HTML-data element bindings that jQuery couldn’t solve on their own. It did work out well in the beginning

However, later on, many things were starting to “crack” beneath the surface. When it comes to the need to scale the application, people are starting to notice the bottleneck performance of UI rendering within the browsers. As your websites grow in greater complexity, the more work the frameworks need to touch DOM elements in manipulating states. Touching actual DOM elements’ is a very expensive operation in any browsers thus people will experience everything from UI blocking, parse-load times increased to greater page timeout errors. Even worse for people who have low mobile data speed connectivity along with small bandwidth, they will be forced to abandon your websites altogether. Therefore you will soon experience the impending death that awaits for your website when your web traffic reaches zero visitors within several weeks.

In other words, people are getting ridiculously demanding for more complex user experiences thus requiring speedier performance that these frameworks aren’t simply cut out to doing it - right out of the box.

This is when (finally - on my actual point) ReactJS turns up on the scene.

ReactJS solely concentrates on building UI of your app (thus the V in the view) which allows you to hyper-extend user experiences when people interact a lot with your apps. ReactJS took the SPA ecosystems to another level that the other frameworks fell short. And that is to do with how it diligently manages the entire state of the app without touching the HTML elements - at all.

Sorry. Back that up.

I don’t mean it truly never touches elements by not lifting its finger. It only touches elements when it needs to when you, as a developer, tell ReactJS where to change on the screen. And it will only make necessary state changes when you explicitly tell it to do so.

ReactJS makes clever use of a diffing algorithm by keeping a copy of the entire FE application tree structure and use it to compare with your original application whenever you’re about to transform state changes at any given point of time. In a tree (like you would when you see an apple tree), you have nodes of the tree. These nodes are the logical representations of your UI elements. Each node can have several child nodes thus UI elements can have other composed UI elements as well (hence React is built around the philosophy of component-based designs). As per ReactJS documentation guide, the core idea behind these component-driven designs is that each node or component keeps their own local states. Each node is responsible to make UI rendering complete whenever a state gets transformed. This same application tree structure is called the Virtual DOM tree as below.

React Virtual Dom Diagram

You see.

How ReactJS fundamentally works is you instruct React which part of the app tree structure that is going to change depending on certain events. This can be anything from API data fetch calls, dependent drop-down fields, table columns filtering, image carousels etc. With any those conditions occurred, ReactJS will take a snapshot of the tree at the time one (or several) of the tree nodes are affected, and use it to compare the previous copy of the tree structure. ReactJS thus makes the comparison between the two; starts to traverse down the tree using the breadth-first search algorithm; identifies the nodes whose states are different to their previous states, and finally, have them initiated the UI re-rendering outputs. By this last step, this is where we get ReactJS to actually touch the DOM API and change them. All the other node’s siblings, parents or ancestors are left untouched. This is all because all nodes are responsible for keeping their own local states, and they will respond or react to the UI changes by themselves when we tell them so.

Hence, that’s how the word “ReactJS” is coined.

ReactJS is brilliantly smart in doing these thus I can understand why the online dev community are loving this so-called new shiny ‘framework’ (though ReactJS concentrates on the View layer, and it’s often mistaken for its comparison to other popular MVC frameworks like Angular). All the states are stored in a Virtual DOM tree. No unnecessary DOM APIs are called anywhere in the same tree when a change is detected. Hence why ReactJS is incredibly fast and you can manage state changes in the DOM tree at almost no cost. You get to utilise its UI rendering lifecycle hooks as well to customise your rendering needs at any node part of your tree as well - straight out of the box.

Where ReactJS shines is where jQuery truly falls short in.

Especially if you’re going to start talking about building FE application to scale at greater accelerated heights, React ticks all the major boxes. Companies of all sizes with varying engineering team size can see the immediate benefits behind them.

With a growing application, you will definitely see the greater need of bringing JS/NPM plugins that can assist with the scalability smoothly. Especially, they complement with ReactJS ecosystem on the upfront.

In this post, I found some great read up on other popular state management libraries that will help you how to work well with React states effectively, depending on the type of app you’re building.

Redux

This is no-brainer. This is the goto-default combo set with React amongst web developers, thanks to the popular Flux-like pattern that gave birth to this ‘invention’. The core idea behind is you do not let ancestors or siblings of any component to take full responsibility of keeping track of state changes along the nodes of the tree. You store the state changes information right at the root of the tree, and any nodes that are interested in knowing what state are changes are done by using Pub-Sub pattern. The key concepts involved are:

  • Actions - payloads of information that describes some action has happened.
  • Reducers - functions whose responsibilities are to change the application states in response to the action that has occurred.
  • Store - is where all the application states reside and act as the global access point for all components who are registered/connected to subscribe event changes that reducers emit.

Pros of Redux

  • Good test coverage
  • Great application predictability using undo/redo history
  • Easy to debug
  • Greater control over dispatch actions and state transformation.

Cons of Redux

  • Too much boilerplate code upfront
  • Reducers/Actions definitions get too verbose quickly

MobX

If you believe Redux is too sophisticated for your application needs when starting out, perhaps this other alternative would be good for you to consider - Mobx. It’s stated to be the simplest, state management library without all the necessary boilerplate Redux enforces you to follow. It builds on 3 concepts. They are:

  • State - are the states of the application
  • Derivations - are the computed values derived from the state of the application
  • Actions - are the ones responsible for altering states

MobX’s design purpose is to allow auto-synchronization between models and UI without requiring any developers’ input to verify states reconciliation. It uses a couple of decorator patterns against functions and data structures so you instruct React to only trigger rendering when data gets observed using @observables. In addition, MobX also offers developers the freedom to do OOP-style around React objects which you could not when using Redux as Redux follows the functional-style programming.

Pros of MobX

  • Ease of Learning and Use
  • Less boilerplate code
  • Old school OOP

Cons of MobX

  • Too much freedom
  • More difficult to debug

Relay + GraphQL

Another popular Flux-inspired state management tool, but with its core focus on harnessing data-fetching capabilities from API servers(usually). It uses advanced concepts of Higher Order Components (HOC) which are defined as wrappers for children components. These same wrappers act as ‘database’ queries from the server (usually of a RESTFUL endpoint); the results of the queries will be stored as props; thus the same props will get pass down to the children components. That database query leverages the so-called query language (invented by FB) called GraphQL, which is query language on graph data structures.

Pros of Relay + GraphQL

  • Good for complex data-fetching queries such as nested data
  • Very powerful and rich data-querying API calls to make

Cons of Relay + GraphQL

  • Only very good for complex data-fetching queries
  • Has a higher rate of learning-curve
  • Overtly-complex for a simple API server to handle

Concluding thoughts

Now you got the gist of why React has become what it is, with everything from the former glory days of web development where being a full-stack developer was far much simpler than it is now. FE experiences are getting more and more advanced in sophistication such as richer user experiences, and the technology that supports those unique experiences are pushing new set of web innovation boundaries. And ReactJS is one of them. It’s not only just the best, also the most promising FE tool that’s gathering a major cult-following amongst the web developer community; thus it is expected to be around for some time, before another ‘shiny’ framework that might come along to dethrone its ranks. Not any time soon - from the looks of it.

But, for now, make the most of the ride, and level up your React knowledge, pay attention to what React communities are up to (just as much I’m trying my best to keep up too while writing this blog post. 😅😅)

Till next time, Happy Coding!

Comments