Skip to main content

Writing Stable JavaScript and React


There is nothing more grating than having your application crash on users because of errors. And while they aren't totally avoidable, let's put together some best practices here that we can follow to reduce these as much as possible.


📘 MDN: Try Catch

Try/catch/finally blocks are well known, but let's just discuss here when we should or should not be using them.

Try catch blocks can make it more difficult to debug where an error is occurring, and as such should not be used totally indiscriminantly (in every function). However there are some times where we absolutely should be using them.

  • Anything involving API queries
  • Anything involving user input
  • When using async/await, try-catch blocks are the standard way to handle asynchronous errors.

Really when it is anytime that we don't have absolute control over our inputs.

Safe Navigation Operator

Use optional chaining (?.) and nullish coalescing (??) to navigate safely through objects.

Optional Chaining

One of the best ways to prevent type errors trying to access properties or values in objects or arrays is optional chaining. Take for example the following:

let someObject = {};
let someVariable = someObject.someProperty.someNestedProperty
// ⚠ TypeError: someObject.someProperty is not defined

To prevent this extremely common scenario from throwing an error we can use optional chaining.

📘 MDN: Optional Chaining 📘 GeeksForGeeks: Optional Chaining

Which if used correctly would look like this

let someObject = {};
let someVariable = someObject?.someProperty?.someNestedProperty
console.log(someVariable); // undefined

We are now returning undefined, and no error.

Optional chaining won't help us in the following scenario, where the object someObject itself is not defined.

// notable absence of someObject declaration here...

let someVariable = someObject?.someProperty?.someOtherProperty
// ⚠ Uncaught ReferenceError: someObject is not defined

The best part is that there is no downside to just using this all the time while trying to access nested methods or variables. Anytime you are trying to access nested items just use the question marks.

Nullish coalescing

Nullish coalescing is an easy way to provide a default value to a variable.

const foo = null ?? 'default string';
// Expected output: "default string"

const baz = 0 ?? 42;
// Expected output: 0

If the value on the left side of the operator is null or undefined then it will return the value on the right side, typically some type of default value.

📘 MDN: Nullish Coalescing Operator

This can be combined with optional chaining to prevent errors while accessing nullish properties and providing a default value.

const foo = { someFooProp: "hi" };

console.log(foo.someFooProp?.toUpperCase() ?? "not available"); // "HI"
console.log(foo.someBarProp?.toUpperCase() ?? "not available"); // "not available"

React Error Boundaries

React error boundaries prevent the entire application from crashing if there are uncaught errors, and can display a fallback ui.

📘 React Docs: Error Boundaries

this can be simplified with a package/component:

📘 NPM: react-error-boundary

and depending on whether you have an error reporting tool installed, they may have their own error boundary component:

Sentry: React Error Boundary

Automated Amazon Reports

Automatically download Amazon Seller and Advertising reports to a private database. View beautiful, on demand, exportable performance reports.