Writing Stable JavaScript and React
Intro
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.
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';
console.log(foo);
// Expected output: "default string"
const baz = 0 ?? 42;
console.log(baz);
// 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:
and depending on whether you have an error reporting tool installed, they may have their own error boundary component:
Comments
Recent Work
Basalt
basalt.softwareFree desktop AI Chat client, designed for developers and businesses. Unlocks advanced model settings only available in the API. Includes quality of life features like custom syntax highlighting.
BidBear
bidbear.ioBidbear is a report automation tool. It downloads Amazon Seller and Advertising reports, daily, to a private database. It then merges and formats the data into beautiful, on demand, exportable performance reports.