The open blogging platform. Say no to algorithms and paywalls.

5 useEffect Infinite Loop Patterns

In general, infinite loops are considered bad practices. But in some edge cases, you don't have any choice other than an infinite loop. It is good to know the infinite loop patterns of React.


When the infinite loop is running without any stop, eventually browser will kill the tab that your code is running. So don't use Infinite Loop without any breaking point.


The useEffect hook allows us to perform side effects in a component. When hooks were introduced the react 16, the useEffect hook gained more traction than any other hooks. Because it provides combined functionalities of componentDidMount, componentDidUpdate and componentWillUnmount life cycle methods.


useEffect hook triggers the callback function, only if the dependencies were changed. And it uses shallow comparison to compare the values of the hook.

You can consider the useEffect as a power stone, it is a most powerful stone and if you haven't handled it properly the stone would destroy you.


Without dependency

useEffect without dependencies generally consider a bad practice, so always try to avoid it.

Consider the following code, it will call the API forever.

What's happening?

If the useEffect is triggering the callback only when the dependencies are changes, why we ended with an infinite loop here.

You need to take into account important another mantra of React which is “When state or Props is changing, the component will re-render”.

In this code, we set the state value using setData on-network call success, it will trigger the component re-render. Since the useEffect doesn't have value to compare, so it will call the callback.

And Again Fetch will trigger setData and setData will trigger, the component re-render and so on.


How to fix this issue?

We need to specify the dependencies as the empty array.

According to official docs, it is not safe to omit the dependencies

Function as dependency

useEffect uses shallow object comparison to determine, whether the data was changed or not. Due to weird JavaScript conditional systems 😈.

Let's consider the following code:

The function getData is passed as dependencies.

When you run this code, it will throw Maximum update depth exceeded which means the code having an infinite loop.


What's happening?

Since useEffect uses the shallow comparison for the compare the values. The shallow comparison for the function will always give false.

How to fix it?

To fix this issue, we need to use another infinity stone called useCallback.


useCallback return a memoized version of callback, which only change when the dependencies change.

Array as dependency

As you might know, the shallow comparison for two is always false, so passing dependencies as an array will also lead to Infinite Loop.

Let's consider the following code:

Here, the array dep passed as dependencies for the useEffect.

When you run this code, the browser console will throw this error.

What's happening?

The shallow comparison of two arrays is always false, so useEffect will always trigger the callback.


How to fix it?

Since the useCallback return is a function, we can't use that.

So, guess what?

We need to use another hook called useRef.


useRef returns a mutable object with .current having the initial value.

Objects as dependency

You might guess the shallow comparison of two objects is always false, so useEffect will trigger the callback always.

Let us consider this code:

data is passed as the dependencies for the useEffect.

When you run this code, your browser console will be thrown an infinity loop error.

What's happening here?

The shallow comparison of objects would be false always, so it will trigger the useEffect's callback.


How to fix it?

If we memoize the dependencies, we break the infinity loop. So how to do that?

Yes, we are going to use another infinity stone called useMemo.


useMemo will only recompute the memoized value when the dependencies have changed.

Wrong dependency

Wrong dependencies are nothing to do with React not even javascript. When the wrong dependencies are used, we must take the blame.

Let us consider the code:

I hope there is no need to explain this issue pattern and its fixes. If you want the explanation and fixes, please let me know in the comment.

Note: There is plenty of ways to avoid infinite loop inside a React component, I mentioned only a few ways.

Always use eslint-plugin-react-hooks or create-react-app, it will help you to find those issues before those get into the production server.

A company lost 72k in a week due to an infinite loop.

So always give special care to our power stone (useEffect).

Further reading: Memoization Demystified in 7 Minutes.

Continue Learning