US & Canada: 877 849 1850
International: +1 678 648 3113

Accelebrate Blog

ACCELERATED LEARNING, CELEBRATED RESULTS

Best Practices for Building JavaScript Applications with React and MobX (Part 1 of 3)

Introduction

When building applications, there are many ways of solving any problem. Mastering a toolset is more than getting it to work, it’s about getting it to work correctly.

Many times, while I am teaching classes and eagerly helping students do their lab exercises, the students will work very hard and creatively to solve a problem, and usually they solve it. Unfortunately, they sometimes solve it by violating core best practices of the tools or patterns being used.

When first learning a new technology, breaking best practices may not seem like a major concern to the student, but their lack of production experience with the technologies has not yet revealed to them the perils of breaking key principles that are in place to ensure the application is built correctly, regardless of size and purpose of the application.

JavaScript is a great language. It is flexible, extensible, and very expressive. Such qualities also lend it to being used in ways it should not be. These qualities translate into errors in coding when using many JavaScript libraries, including React and MobX. The following 3-part series will present 7 Best Practices recommended for building applications with JavaScript, React, and MobX. Each post in the series will have 2-3 Best Practices described in great detail.

Best Practice #1 – Declaring Variables

Before ES2015 (aka ES6), the only way to declare variables was by using the var keyword. Variables declared with var were mutable, meaning their values could be changed. With the advent of ES2015, two new keywords were defined for declaring variables: const and let.

const declares immutable variables and let declares mutable variables. This distinction (and a few other unrelated features of these two keywords) have greatly benefited JavaScript. They allow a clearer intent of the purpose and usage of the variables within a JavaScript application. Many times, my students will ask me the preferred way to declare variables: is it var, const, or let?

Variables for new code should never be declared with var. When working with old code, var declarations should be replaced with const or let, as appropriate. There is no good use case for using var, and while it is still supported by JavaScript engines for backward compatibility, it should never be used. Nevertheless, because there is so much legacy code still in use today, every JavaScript developer should know the details and implications of using var, such as declaration hoisting and function scope.

Since var will not be used, should const or let be used? Answer: all variables should be declared with const unless they will be intentionally mutated. Many developers mentally equate const with the compile-time constants found in other languages such as C or C++. The JavaScript const is not a compile-time constant; it is a run-time constant. Using const communicates to other developers the intended immutable purpose of the variable and helps to clarify the flow of data. Variables that will never change, which will be most of them, should be configured as such.

The keyword let should only be used in situations where the mutation is intentionally planned. Examples include incrementing a counter or declaring a variable above an if or switch block and assigning a value based upon the control flow where the value will be used after the control block has completed.

// do not use
var a = 2;

// variable is immutable
const b = 2;
b = 3; // throws an error

// variable is mutable
let c = 2;
c = 3; // allowed

It’s good to keep in mind that JavaScript is primarily a functional programming language, and most functional languages leverage immutable variables, not mutable variables. Even in the examples above for mutating, functional programmers would argue for more functional approaches to structures instead of if and switch control flow blocks.

Best Practice #2 – Immutable Programming with Objects

One of the many challenges of user interface programming is solving the problem of change detection. There are many strategies for solving this issue, including:

  1. Do not detect changes and re-render everything
  2. Detect changes through value and object reference comparison
  3. Detect Changes through tracking property access

By default, the React library uses the first strategy. It’s easy to implement, but inefficient. For relatively small component trees, it works fine, and any inefficiencies are not noticed by the user.

Note: Re-render does not necessarily mean re-rendering the real DOM tree. With React, the re-rendering discussed here is the in-memory Virtual DOM tree. The updates to the real DOM still occur through the optimized reconciliation process, meaning the real DOM tree is not necessarily completely re-rendered and is only updated as needed. While React, by default, inefficiently updates the Virtual DOM, it always updates the real DOM efficiently.

The second strategy is employed by React’s Pure Component and state management libraries such as Redux. It is efficient for performing change detection, but requires developers to faithfully work with objects (including arrays) using immutable programming techniques. The “faithfully” part is key here because, in many cases, there is no effective or efficient coding mechanism to ensure immutable programming techniques are being used. Code reviews and proper developer training is critical.

The third technique is used by state management libraries such as MobX. This technique requires less work on the part of the developer, but it employs more “magic” to perform the tracking. It can break if developers do not work with objects (and specifically the object’s properties) correctly.

Note: We all know there is no such thing as magic when it comes to programming. All code is logical, and the processor executes the code logically. By “magic,” this means the logic is not clear to the average developer and can result in mistakes which were not obvious. The mistakes are not violations of JavaScript itself, but rather violations of the stricter rules about the “magic” code. Debugging the errors caused by these violations is especially difficult because the developer does not understand what they did wrong because the code’s limitations are not clear.

In general, using immutable programming techniques in JavaScript applications for working with objects (including arrays) is a good idea. Normally, if objects are treated as immutable, then the application can leverage the performance enhancements of detecting changes more quickly. Fortunately, most of the tools used in JavaScript to work with objects immutably are built into JavaScript itself, which means they will be very fast at run-time.

Note: It is always better to use built-in JavaScript APIs than to use the equivalent library written in JavaScript. JavaScript APIs will execute your code and process your data with highly optimized C++ code at a low-level in the JavaScript engine. Writing a similar function in JavaScript will always run more slowly. For example, the Promise API built into JavaScript is always better than the Promise API implemented in pure JavaScript and included as a JavaScript library. Only transpile back to the version of JavaScript you must support. Going back too many versions will replace efficient code understood by modern JavaScript engines with inefficient polyfills that mimic a new built-in feature. If you are using Babel the new environment configuration option where the supported browsers are specified is a great way to only transpile what you need while keeping more of your code using the newer native features.

Working with objects immutably is relatively simple. For example, instead of using push, pop, shift, unshift and slice to add and remove items from an array, the immutable functions slice and concat should be used.

// mutable operations
const nums = [ 1, 2, 3, 4 ];

// array mutated to [ 1, 2, 3, 4, 5 ]
nums.push(5);

// array mutated to [ 1, 2, 3, 4 ]
nums.pop();

// array mutated to [ 1, 2, 9, 4 ]
nums.splice(2, 1, 9);
// immutable operations
const oldNums = [ 1, 2, 3, 4 ];

// oldNums: [ 1, 2, 3, 4 ]
// newNums: [ 1, 2, 3, 4, 5 ]
let newNums = oldNums.concat(5);

// oldNums: [ 1, 2, 3, 4 ]
// newNums: [ 2, 3 ]
newNums = oldNums.slice(1,3);

Also, the array spread and rest operators can be used to produce new arrays when adding and removing items.

// immutable operations with spread and rest
const oldNums = [ 1, 2, 3, 4 ];

// oldNums: [ 1, 2, 3, 4 ]
// removeItem: 1
// newNums [ 2, 3, 4 ]
const [ removeItem, newNums ] = oldNums;

// oldNums: [ 1, 2, 3, 4 ]
// newNums [ 1, 2, 3, 4, 5 ]
const newNums = [ ...oldNums, 5 ];

When updating object properties, the function Object.assign can be used. If a project is using Babel or TypeScript to transpile the JavaScript code, the object spread operator can be used in place of Object.assign.

// Examples of Object.assign and Object Spreads
const oldPerson = {
  firstName: 'Bob',
  lastName: 'Smith',
};

// oldPerson => { firstName: 'Bob', lastName: 'Smith' }
// newPerson => { firstName: 'Jane', lastName: 'Smith' }
let newPerson = Object.assign({}, oldPerson, { firstName: 'Jane' });

// oldPerson => { firstName: 'Bob', lastName: 'Smith' }
// newPerson => { firstName: 'Jane', lastName: 'Smith' }
newPerson = { ...oldPerson, firstName: 'Jane' };

One of the great challenges of immutably working objects is updating an object deep within an object tree. When an object is updated deep in the tree, a new object is needed for that object, as well as every ancestor object above it in the tree. It’s important to keep the object tree from growing too deep, otherwise performing immutable operations is very painful.

Several libraries exist to help with immutable operations. One of the more popular ones is Immutable.js, provided by Facebook.

Conclusion

The “best” best practice of any React or MobX developer is to deeply learn JavaScript. Most students have few problems with learning React or MobX but struggle greatly with the JavaScript used to code with both technologies. In this post, two specific best practices regarding variables and immutable objects were examined. In future posts, best practices regarding React components and managing application state with MobX will be explored. Do you have any best practices from your experiences? Do you disagree with any of the practices listed in this blog post? If so, please tell us in your comments below.

Continue to Part 2


Author: Eric Greene, one of Accelebrate’s instructor

Accelebrate offers private React/Redux training for groups and instructor-led online JavaScript classes for individuals.  Visit https://www.accelebrate.com/react-training to see the full list of courses.

Categories: JavaScript Articles
Tags: , , , , , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

Your email address will not be published. Required fields are marked *

*



You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Please contact us for GSA pricing.
Contract #GS-35F-0307T

Please see our complete list of
Microsoft Official Courses