This article intends to inform beginners using the react library to create single page applications about potential pitfalls they may run into even though their react code appears to be good or at least they have followed the normal techniques.
The best react practices could be using the proper react hooks, passing components the proper props, and mapping values to jsx, but when the code is executed, there is always an uncaught error or something that is undefined.
In this article, we will look out at the following JavaScript pitfall
-
null
andundefined
values - Falsy values.
- Default parameters
- Enumerating an object literal
- React Error boundary
1. Always check for null
and undefined
values before setting state or passing props.
In JavaScript, there are two peculiar data types: null
and undefined
. These data types have no attributes or methods and always equal themselves. When executing statements and evaluating expressions, they are helpful to web developers.
Undefined is used to represent values that have not yet been assigned, and null is used to represent values that are missing. When JavaScript is unable to locate the appropriate data type, they are a fallback data type that is used.
usage
Optional chaining and null coalescing operators were added to JavaScript ES2020 to reduce problems brought on by the existence of null or undefined. Like ternary operators, they are conditional operators that only accept and evaluate one operand. These capabilities, which keep applications resilient to runtime missing values, have acquired enormous popularity in the JavaScript community in the past three years.
Optional chaining (?.)
, also called short circuit in C#, it checks for a property or method of a data type, if it’s present it will display or execute a statement ,if it’s absent it will return undefined or rather it short circuits. Initially, this would throw an error that breaks the application. This therefore allows the developer to check for undefined or null.
let user = null; // say, we're expection user object from server, we start with null first
// ternary operator renders conditionally, if user there render name else no user found
<p>{user ? ` Hello ${user.name} ` : "No user found"} </p>;
//optional chaining assumes the value is there and if its not there render null or undefined
<p>{ user?.name } </p>;
Null coalescing (??)
,on the other hand, does a soft substitution, for null or undefined values in a variable with a fallback value.
const user = null ?? {name: "Mark Twain", id: 2 };
These features in React make interpolating state to jsx easier because fewer ternary operators and "if" statements are required. Before creating state, passing props, and inside jsx interpolation—before rendering jsx elements—it is crucial to check for and/or against these values.
We can use both operators in jsx expression as such;
<p>{user?.name ?? "User"} <p>
2. Watch out for falsy values
You will constantly come across false values, and you have probably used them in some way. It's important to start off by pointing out that values in JavaScript are booleans that can only have a value of true or false.
Falsy values are values that evaluate to false and there are 9 falsy values in javascript namely:
null, undefined, NaN,0,-0,
(empty template strings),false, [] “”, (single and double empty string).
Truthy values are values that evaluate to true e.g numbers, non-empty strings and object literal.
False values are a Javascript programmer's best friend for evaluating expressions, running statements, and doing data validation in situations where the user must provide input.
Using the built-in Boolean method, you can check for erroneous values. Using the console, log (Boolean(null)).
/* assume we are waiting for a user object from the backend, user to log in or so,initially its null */
const user = null;
if (user) console.log(`welcome ${user?.name}`);
else console.log(`welcome user,kindly login`);
// checking against falsy values
if (user?.name !== undefined) console.log(`welcome ${user?.name}`);
else console.log(`welcome user`);
When making a REST API request in React, initialise all objects with null, empty curly braces, and empty arrays. This makes it simple to tell when the payload has arrived and can then be checked by determining whether a variable is true or false.
3. Set default prop parameters in components.
React is so quick at rendering components that occasionally it may render a value that is not yet accessible, such as the payload of a pending network request. For missing values in this scenario, the code will fallback to null or undefined.
JavaScript ES6 introduced default parameters for handling edgy cases in parameters supplied to function definitions.
Default parameters are fallback values (empty array, string, or object) for variables whose values are not yet accessible at the time of execution, enabling JavaScript interpreters to query for those methods and properties.
They could have any data type or start value. Null and undefined can be used as default parameters as long as a check is made to see if the values are still accurate. Your function arguments should be indicated with an equal sign and the value to add a default parameter.
const addNumbers=(a=1,b=1)=>a +b;
A react component utilising default parameters
function RenderPosts({ posts = [] }) {
/* posts uses an empty array as default value, it will not be replaced by undefined in case posts payload doesn't arrive */
return (
<ul>
{posts.length > 0 ? (
posts.map((post) => <li key={post.id}>{posts.title}</li>)
) : (
<li>No Post found</li>
)}
</ul>
);
}
// javascript function
const renderUser = ({ user = null }) => {
// we check for an object which will be truthy if its present
if (user)
return (
<div>
<h3>Name: {user?.name}</h3>
<p>Title: {user?.title}</p>
</div>
);
return user // we render null if user is null which a default parameter
};
Javascript function with default params
// this function greets the user if their name is present else just calls them ninja
const greetUser = (username = "Ninja") => ` Hello ${username}, welcome to the Metaverse.`;
greetUser("Darth Vader") // Hello Darth Vader, Welcome to the Metaverse.
GreetUser() // / Hello Ninja, Welcome to the Metaverse.
4. Always check the shape of the object literal before rendering.
An object in JavaScript is a collection of key-value pairs, often known as a property. An object is anything that isn't a number, string, undefined, symbol, or Boolean.
By the way, null is always treated as an object. typeof null //object
In Javascript, there are three different sorts of objects: functions, arrays, and object Literal.
The payload properties that are contained in object literals, however, may originate from a REST api or user input, therefore it is vital to check for them before displaying. In react, we always assume and verify that every object has an id attribute.
let user=null // initially user object its null
async function fetchUser () {
// we're fetching user with id number 1;
const url = "https://jsonplaceholder.typicode.com/users/1";
try {
const response = await fetch(url);
const payload = await response.json();
// check if object exists by checking if id property is not undefined..
// also note the optional chaining, if nothing returned, if payload is null or undefined,
//it will just end there;
if (payload?.id !== undefined) return payload
} catch (error) {
console.error(error?.message);
}
}
// fetch user when the DOM loads
window.addEventListener("DOMContentLoaded", async ()=>{
user= await fetchUser() // asynchronous network request to get a user object
})
Here are 3 ways to evaluate properties of an object.
- Using the in method
The in JavaScript method checks if the property exists in an object,returns true if present,false if absent
if("id" in user)
console.log(` ${user.id} found `)
else
console.log(`The property does not exist`)
- Checking if certain object property is undefined
If a property does not exist, it will always be undefined,so to check we do this.
// in our case we’re checking if user has property id
if (user.id !== undefined) console.log(` ${user.id} found `);
else console.log(`The property does not exist`);
- Using has hasOwnProperty method
This is a built in method that takes the object, its property and tests for its presence, return true or false.
if (user.hasOwnProperty("id")) console.log(` ${user.id} found`);
else console.log(`user does not exist`);
Here is a whole React component performing the 3 checks above
function RenderPost() {
const [post, setPost] = React.useState({}); // we start with an empty object literal
const [spinner, setSpinner] = React.useState(false);
// we're fetching one post
const fetchPost = async (postId = 1) => {
try {
setSpinner(true);
const url = `https://jsonplaceholder.typicode.com/posts/${postId}`;
const response = await fetch(url);
const payload = await response.json();
// check if object exists by checking if id property is not undefined..
if (payload?.id !== undefined) setPost(payload);
setSpinner(false);
} catch (error) {
setSpinner(false);
console.error(error?.message);
}
};
React.useEffect(() => {
// if the post is empty just fetch it, we use negation symbol to do that
if (!post.hasOwnProperty("id")) fetchPost(1);
}, []);
// pending state
if (spinner)
return (
<div className="container">
<p>Loading post</p>
</div>
);
// resolved or rejected
return (
<div className="container">
{/**We use the in Method to check if object has id property */}
{"id" in post ? (
<div>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>
) : (
<p>No post found</p>
)}
</div>
);
}
5. Add Error boundaries to your react application
React Error Boundaries is a graceful way to handle a JavaScript error on the client so that the other parts of the application continue working. In addition to preventing the page from crashing, it allows you to provide a custom fallback component and even log error information. * copied this statement from next js website*
Error boundaries make sure that your application is resilient in the face of unforeseen errors from tiny defects that escaped during development, network request, or event-related problems. They are essential for identifying faults that the JavaScript interpreter is unable to detect while the programme is running.
To use Error Boundaries for your Next.js application, you must create a special React class component ErrorBoundary
and wrap around your react application or specific parts of your app.
The class accepts a custom fallback functional component as a prop that will be shown to the user when an error occurs. The error boundary contains a unique function and state that sets an error object, which is subsequently sent to the fallback component.
import React, { Component } from "react";
export default class ErrorBoundary extends Component {
state = { error: null };
static getDerivedStateFromError(error) {
// it will set state automatically if there’s an error caught
return { error };
}
render() {
const { error } = this.state;
const { children, fallback } = this.props;
if (error) return <fallback error={error} />;
return children;
}
}
export const ErrorFallbackComponent=({error})=>{
// we display custom error UI here
// we can also send error message to an issue management app from here
return (
<div>
<h3>Something went wrong</h3>
<p>{error?.message}</p>
</div>)
}
The ErrorBoundary component keeps track of an error
state. The value of this state variable is a boolean. When the value of error
is true, then the ErrorBoundary component will render a fallback UI. Otherwise, it will render the children components.
Finally, wrap our error boundary component to our app and pass the fallback component as prop. Our component will now catch all errors and render a custom fallback UI.
// app.js
Import ErrorBoundary, {ErrorFallbackComponent} from “./ErrrorBoundary”
<ErrorBoundary fallback={ ErrorFallbackComponent}>
<App/>
</ErrorBoundary>
You can read my blog on how to utilize React error boundary class with Google Analytics to track production errors in React apps
Top comments (0)