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.
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.
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:
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.
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.
Accelebrate offers private React/Redux training for groups and instructor-led online JavaScript classes for individuals.
Written by 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.
Our live, instructor-led lectures are far more effective than pre-recorded classes
If your team is not 100% satisfied with your training, we do what's necessary to make it right
Whether you are at home or in the office, we make learning interactive and engaging
We accept check, ACH/EFT, major credit cards, and most purchase orders
Alabama
Birmingham
Huntsville
Montgomery
Alaska
Anchorage
Arizona
Phoenix
Tucson
Arkansas
Fayetteville
Little Rock
California
Los Angeles
Oakland
Orange County
Sacramento
San Diego
San Francisco
San Jose
Colorado
Boulder
Colorado Springs
Denver
Connecticut
Hartford
DC
Washington
Florida
Fort Lauderdale
Jacksonville
Miami
Orlando
Tampa
Georgia
Atlanta
Augusta
Savannah
Hawaii
Honolulu
Idaho
Boise
Illinois
Chicago
Indiana
Indianapolis
Iowa
Cedar Rapids
Des Moines
Kansas
Wichita
Kentucky
Lexington
Louisville
Louisiana
New Orleans
Maine
Portland
Maryland
Annapolis
Baltimore
Frederick
Hagerstown
Massachusetts
Boston
Cambridge
Springfield
Michigan
Ann Arbor
Detroit
Grand Rapids
Minnesota
Minneapolis
Saint Paul
Mississippi
Jackson
Missouri
Kansas City
St. Louis
Nebraska
Lincoln
Omaha
Nevada
Las Vegas
Reno
New Jersey
Princeton
New Mexico
Albuquerque
New York
Albany
Buffalo
New York City
White Plains
North Carolina
Charlotte
Durham
Raleigh
Ohio
Akron
Canton
Cincinnati
Cleveland
Columbus
Dayton
Oklahoma
Oklahoma City
Tulsa
Oregon
Portland
Pennsylvania
Philadelphia
Pittsburgh
Rhode Island
Providence
South Carolina
Charleston
Columbia
Greenville
Tennessee
Knoxville
Memphis
Nashville
Texas
Austin
Dallas
El Paso
Houston
San Antonio
Utah
Salt Lake City
Virginia
Alexandria
Arlington
Norfolk
Richmond
Washington
Seattle
Tacoma
West Virginia
Charleston
Wisconsin
Madison
Milwaukee
Alberta
Calgary
Edmonton
British Columbia
Vancouver
Manitoba
Winnipeg
Nova Scotia
Halifax
Ontario
Ottawa
Toronto
Quebec
Montreal
Puerto Rico
San Juan