My most frequent React errors and how you fix them

Blog post cover

When using the popular JavaScript library React there are some errors/problems that seem to pop up time and time again. They can be easily avoided in most situations and I would like to share them with you so you can spend less time debugging and more time writing code.

So let's not waste any time and take a look at our problems and how we can solve them ๐Ÿ‘.

Content

  1. Forgetting to add keys with a list of elements
  2. Not returning a list correctly
  3. Not cleaning up certain useEffect side-effects
  4. Not wrapping adjacent JSX elements

1) Forgetting to add keys with a list of elements

In React we often find ourselves with lists of data that we want to map into elements or components. This is often done using the Array.prototype.map function to pass data from each index of the array to the element or component through props.

When we do this without adding a key prop React will complain that each element is missing a key. Essentially it is just a special attribute to which we pass a string. It should be a unique string which will distinguish it from its siblings that we are also mapping.

React says:

Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity

Example Problem

Let's map some data before adding keys to our elements to see the problem in action. Here we will have a simple component that deconstructs foods from the prop object. foods is just an array of objects and it looks like this ๐Ÿ‘‡

Our example data set

and our component ๐Ÿ‘‡

mapped elements without key prop

and finally the warning from React ๐Ÿ‘‡.

missing key warning

Solution

To fix this all we have to do is pass a unique key to the element we are returning. Often the data we are mapping comes from a fetch request and usually includes an id. Fortunately we have and id property we can use from our set of data. Let's add our key property.

After adding our key prop

If we didn't have a unique id we would need to have an alternative solution. Often people use the index of the array as the key but this is not recommended for any set of data where positions in the list may change. It can negatively affect the state of the component. See here for more information Reactjs - Reconciliation.

Instead we could create our key by combining the name property with the current date/time using the JavaScript Date object. You could also use a package like nanoid that generates unique string id's for you.

2) Not returning a list correctly

To return or not to return

In React as we have already seen we are often iterating over some data . Perhaps we are filtering a data set down to a specific sub-set or mapping to the DOM. Whatever it is there are a few pitfalls we need to watch out for when it comes to returning our data otherwise we might be left scratching our heads.

Example Problem

A frustrating example can be seen when we map a data set to some elements or components. We expect to see the or elements on screen with the data we map into them. However we see nothing.

No error, no warning no data ๐Ÿคจ. In this situation it is likely that you're not returning your result correctly.

For our example we will be mapping our array of foods to some elements so we can show it to the user. It should look like this:

Correct return demonstration

Instead our data will appear to be missing ๐Ÿ‘‡.

Incorrect return demonstration

Let me show you some examples where we won't see the output that we were expecting. We are passing our array to our component and destructuring it from the prop object the same as before.

Can you spot the problem below.

Example of not returning correclty

Correct! Here we are not returning anything either implicitly or explicitly using the return keyword.

Let's take a look at another ๐Ÿ‘‡.

Second example of not returning correctly

This time we include the return keyword but what we are actually doing here is returning undefined. The code below the return statement never gets read.

There are other examples you might run into but let's take a look at the different solutions we can use.

Solution

Let's start with the explicit returns. If we move our article element in line with the return statement all is well.

See below ๐Ÿ‘‡

Example of correct explicit return

We could also wrap the return elements with parenthesis like this:

Example of correct explicit return

Another option is to return the result implicitly which means we can forget the return statement and the function body curly braces. Check it out ๐Ÿ‘‡.

Example of correct implicit return

or inline like this ๐Ÿ‘‡.

Example of correct implicit return

The choice is up to you as long as you are aware of the possible pitfalls you encounter. If the data appears to be missing make sure you check your map function carefully and make sure you are actually returning correctly.

3) Not cleaning up certain useEffect side-effects

The useEffect hook allows us to perform side-effects inside functional components. Certain side-effects that we perform in this hook require cleanup. This means that when the component unmounts we can run a special function. Sometimes this is necessary otherwise we might see an error warning us of memory leaks in our apps.

Consider a useEffect that performs some kind of asynchronous api call before setting some component state to the response. If the response is slow and the component unmounts before we receive a response then we might be trying to update the state of a component that is not mounted.

Example Problem

Let's take a look at two different situations where we might add some cleanup to our useEffect.

The first is a situation is where we have an asynchronous fetch request inside our useEffect hook. The user of the application navigates to a different page before we receive the response from the fetch call. This is our component before we add a cleanup function to theuseEffect hook.

React useEffect before cleanup

Here we are fetching some data after the component mounts and then using the result to set the components state. Finally we map the state to the DOM. Relatively straight forward ๐Ÿ‘.

The second situation is where we add some eventListeners to some DOM elements. If the component unmounts we are going to want to remove these listeners.

Check it out before we clean it up ๐Ÿ‘‡

Before adding our cleanup function to useEffect

The logic inside our useEffect is irrelevant for this simple example. All that matters is that we are adding an event listener and that will need to be cleaned up.

Solution

We begin by adding a cleanup function to our useEffect like this:

useEffect cleanup function

It is simply a function that we add to the bottom of our useEffect hook where we add our cleanup logic.

Now to cleanup our fetch request we can use the DOM api AbortController which is available in JavaScript. It allows us to abort web requests which we will use to abort out of the fetch request whenever the component unmounts. Let's see it in action ๐Ÿ‘‡.

React useEffect fetch cleanup function

First we create a controller by using the constructor with new AbortController() and then we pass its property signal to the fetch request. This association of controller signal to the request allows us to abort the request by calling abort() inside the cleanup function.

Now we are ensuring that we don't have any requests coming back to a component that is not mounted.

The cleanup function for our eventListener example is simple which you might have already guessed. All we need to do is remove any listeners we create using removeEventListener in our cleanup function. Let's see it in action ๐Ÿ‘‡.

React useEffect listener cleanup example

Hopefully now like me you won't forget to clean up your effects ๐Ÿ˜‰.

4) Not wrapping adjacent JSX elements

This one is simple to debug but I though I would include it because I sometimes forget to do it until React starts shouting at me ๐Ÿ˜….

Adjacent JSX elements must be wrapped with an enclosing tag. There are a few different ways we can do this based on our requirements.

Example Problem

If we want the wrapper to be part of the DOM for structural purposes then go with some semantic element where possible (<article>, <section> etc.). I usually wouldn't recommend wrapping elements with a <div> although it is fine if you want the wrapper for styling purposes.

Often we do not want the wrapper to part of the DOM because it serves no purpose there. We would only be adding markup only to shut React up.

Let's see the problem in action.

Example component not wrapping adjacent JSX

and the error it throws ๐Ÿ‘‡

Adjacent JSX error

It is likely that your code editor gave you a warning about this before the error pops up which is great.

Solution

Fortunately React provides us with a solution. We can use React.Fragment to wrap our adjacent JSX if we do not require the wrapper to be part of the DOM. Let's say this is the case for the following example.

First let's use React.Fragment before we see how we can simplify it further.

Wrapping adjacent JSX with React.Fragment

If we don't need any attributes or keys for our fragment we can shorten React.Fragment to this <> empty tag. Have a look below.

Wrapping adjacent JSX with React.Fragment shortened syntax

Finally if we are mapping some data to JSX as we have previously seen then we need to add keys to our wrapping element. If all we have is adjacent JSX then we can wrap our elements with React.Fragment and add a unique key to the fragment.

Wrapping our mapped adjacent JSX with React.fragment and a unique key

Conclusion

Thanks for getting this far! I hope you learned something from the article and now we can both make sure we avoid these problems in our future code.

If you enjoyed it feel free to drop a ๐Ÿ‘ on the article. It inspires me to continue improving and make more awesome content.

If you would like to connect with me then come an say hi @Kieran6dev as I am always active in communicating with other devs over on Twitter.

Thanks!