Managing state is a major challenge in front-end web development. As a freelance front-end developer, I’m always striving to synchronize the state object with its visual representation in the DOM. With diverse user interactions, ensuring smooth transitions between states is crucial.

A Look Back
Web applications were once simpler. The browser sent requests to the server, which handled all the logic and returned complete HTML views. User actions like clicks or form submissions initiated the same cycle. State management wasn’t a concern, and new requests regenerated views.
However, as applications and UI/UX expectations evolved, full-page reloads became inefficient. We needed fast, dynamic interactions with instant UI updates.
JavaScript came to the rescue. Developers shifted significant logic to the browser. jQuery simplified tasks like client-side validation, modal windows, animations, and Ajax-based partial updates.
Complexity Explained
Consider a simple password strength checker. A green border and message indicate a strong password, while a red border and warning indicate weakness. A smiley face might appear for sufficient strength.
DOM manipulation can achieve this, but it involves complex code with numerous conditions.
| |
As demonstrated, we check for an empty password and update related DOM elements (message, border, smiley face).
Our password field has three states (empty, weak, strong) affecting three DOM elements. Managing these combinations increases cyclomatic complexity even in this simple scenario.
The DOM’s retained mode only stores the current state. Modifying the view requires instructions for each DOM element and transition programming.
Coding transitions instead of states becomes cumbersome. The number of checks grows exponentially with view states, leading to code bloat. In our example, three states result in six transitions (3 * 2 = 6). Generally, N states lead to N * (N - 1) = N^2 - N transitions. Imagine the complexity with a fourth state!
Excessive code focuses on transitions. Directly defining view states would be more efficient.
Simplifying Complexity
Declaring view states based on the model state simplifies the process.
| |
Three code branches represent the app’s possible states. We return the desired view specification based on the model state, eliminating DOM manipulation. We define what we want, not how to achieve it.
This reduces complexity but assumes an external entity handles DOM manipulation.
That’s where React shines. React automatically manages and updates the view state based on the data model.
React in Action
React, a JavaScript library by Facebook, handles the UI (the V in MVC). It focuses solely on rendering components, integrating seamlessly with other technologies.
React allows defining UIs as nested components. Developers use a render function to describe components based on input state. This function should be pure (no side effects, only explicit input dependency).
The render function returns a Virtual DOM – a JavaScript object mirroring the rendered DOM.
Changing a component’s state triggers a re-render of itself and its children, generating a new Virtual DOM.
React doesn’t simply replace HTML during transitions. It calculates the difference between states and executes the most efficient DOM operations.
Beyond performance, reduced complexity lets us focus on intricate application aspects.
Here’s our password strength example using React:
NOTE: This code uses the JSX preprocessor, common for React UIs.
| |
The <Emoji value="smiley" /> component, rendered for sufficient strength, is another custom component like PasswordWithStrength:
| |
React.js vs. the Rest
Other JavaScript frameworks (Ember, Angular, Knockout) also manage view states. Why choose React?
No Data Binding
Some frameworks use data binding to synchronize DOM elements and state properties. React doesn’t. Developers call setState or re-render the top component upon state changes, embracing a one-directional flow.
This is intuitive, as developers typically focus on data representation. No need to worry about dependent properties, formatting, or binding complexities. Simply re-render on model changes.
Let’s compare Ember and React by creating a person object displaying the full name in uppercase, updating after two seconds:
| |
Ember observes property changes, requiring us to specify fullName’s dependency on firstName and lastName using .property('firstName', 'lastName').
After two seconds, person.set('firstName', 'Harry'); triggers the view update.
Now in React:
| |
Ember’s code is clear, but React is simpler. The person is a plain object, with fullName as a function.
No Templating
Frameworks handle templates differently, using strings compiled to JavaScript, direct DOM manipulation, or custom attributes compiled into HTML.
Templates exist outside JavaScript, requiring custom syntax for common operations. React uses plain JavaScript, leveraging its full power for view generation. JSX (optional) converts “HTML-like syntax” to JavaScript.
Let’s compare React with AngularJS by listing hashtags and their tweet counts, sorted by count, with a message for no hashtags:
| |
This requires learning AngularJS directives (ng-show, ng-repeat) and filters (orderBy).
The React equivalent:
| |
Even with JSX, the code is understandable for any JavaScript developer. Standard constructs like if, map(), and sort() eliminate the need for special syntax.
In Conclusion
React simplifies development by focusing on view state management, not transitions.
Learning React is straightforward: no custom templating, no data binding headaches, just plain JavaScript functions describing UI elements.
For a deeper dive into React’s code simplification, watch Steven Luscher’s talk: Decomplexifying Code with React.
Ready to explore further? Check out these resources: