DEV Community

Cover image for 5 JavaScript pitfalls that beginners using React should be aware of.
Vincent Kipyegon
Vincent Kipyegon

Posted on

5 JavaScript pitfalls that beginners using React should be aware of.

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

  1. null and undefined values
  2. Falsy values.
  3. Default parameters
  4. Enumerating an object literal
  5. 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>;
Enter fullscreen mode Exit fullscreen mode

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`);
Enter fullscreen mode Exit fullscreen mode

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
};

Enter fullscreen mode Exit fullscreen mode

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.

Enter fullscreen mode Exit fullscreen mode

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
})

Enter fullscreen mode Exit fullscreen mode

Here are 3 ways to evaluate properties of an object.

  1. 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`)
Enter fullscreen mode Exit fullscreen mode
  1. 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`);
Enter fullscreen mode Exit fullscreen mode
  1. 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`);
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>)
}

Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

You can read my blog on how to utilize React error boundary class with Google Analytics to track production errors in React apps

Oldest comments (0)