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

November 01, 2017 in JavaScript Articles

Written by Eric Greene


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


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


Written by Eric Greene

Eric Greene

Eric is a professional software developer specializing in HTML, CSS, and JavaScript technologies. He has been developing software and delivering training classes for nearly 19 years. He holds the MCSD Certification for ASP.Net Web Applications, and is a Microsoft Certified Trainer.



Contact Us:

Accelebrate’s training classes are available for private groups of 3 or more people at your site or online anywhere worldwide.

Don't settle for a "one size fits all" public class! Have Accelebrate deliver exactly the training you want, privately at your site or online, for less than the cost of a public class.

For pricing and to learn more, please contact us.

Contact Us Train For Us

Toll-free in US/Canada:
877 849 1850
International:
+1 678 648 3113

Toll-free in US/Canada:
866 566 1228
International:
+1 404 420 2491

925B Peachtree Street, NE
PMB 378
Atlanta, GA 30309-3918
USA

Subscribe to our Newsletter:

Never miss the latest news and information from Accelebrate:

Microsoft Gold Partner

Please see our complete list of
Microsoft Official Courses

Recent Training Locations

Alabama

Huntsville

Montgomery

Birmingham

Alaska

Anchorage

Arizona

Phoenix

Tucson

Arkansas

Fayetteville

Little Rock

California

San Francisco

Oakland

San Jose

Orange County

Los Angeles

Sacramento

San Diego

Colorado

Denver

Boulder

Colorado Springs

Connecticut

Hartford

DC

Washington

Florida

Fort Lauderdale

Miami

Jacksonville

Orlando

Saint Petersburg

Tampa

Georgia

Atlanta

Augusta

Savannah

Idaho

Boise

Illinois

Chicago

Indiana

Indianapolis

Iowa

Ceder Rapids

Des Moines

Kansas

Wichita

Kentucky

Lexington

Louisville

Louisiana

Banton Rouge

New Orleans

Maine

Portland

Maryland

Annapolis

Baltimore

Hagerstown

Frederick

Massachusetts

Springfield

Boston

Cambridge

Michigan

Ann Arbor

Detroit

Grand Rapids

Minnesota

Saint Paul

Minneapolis

Mississippi

Jackson

Missouri

Kansas City

St. Louis

Nebraska

Lincoln

Omaha

Nevada

Reno

Las Vegas

New Jersey

Princeton

New Mexico

Albuquerque

New York

Buffalo

Albany

White Plains

New York City

North Carolina

Charlotte

Durham

Raleigh

Ohio

Canton

Akron

Cincinnati

Cleveland

Columbus

Dayton

Oklahoma

Tulsa

Oklahoma City

Oregon

Portland

Pennsylvania

Pittsburgh

Philadelphia

Rhode Island

Providence

South Carolina

Columbia

Charleston

Spartanburg

Greenville

Tennessee

Memphis

Nashville

Knoxville

Texas

Dallas

El Paso

Houston

San Antonio

Austin

Utah

Salt Lake City

Virginia

Richmond

Alexandria

Arlington

Washington

Tacoma

Seattle

West Virginia

Charleston

Wisconsin

Madison

Milwaukee

Alberta

Edmonton

Calgary

British Columbia

Vancouver

Nova Scotia

Halifax

Ontario

Ottawa

Toronto

Quebec

Montreal

Puerto Rico

San Juan

© 2013-2019 Accelebrate, Inc. All Rights Reserved. All trademarks are owned by their respective owners.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.