How To Prevent Infinite Loops When Using Useeffect in ReactJS
How To Prevent Infinite Loops When Using Useeffect in ReactJS
ReactJS
freecodecamp.org/news/prevent-infinite-loops-when-using-useeffect-in-reactjs
Roy Chng
The useEffect hook in React has become a common tool for managing side
effects in functional components. But there's a common pitfall when using it: the
potential for infinite loops. These can cause performance issues and disrupt the
intended behavior of components.
In this tutorial, we will explore how to prevent infinite loops when using useEffect in React.
You use the useEffect hook in functional components in React to manage side effects, such
as fetching data from an API, updating the DOM, or subscribing to events that are external to
React.
Missing Dependencies
One common mistake that can cause infinite loops is not specifying a dependency array.
useEffect checks if the dependencies have changed after every render of the component.
1/8
So, when no dependencies are provided, the effect will run after every single render, which
can lead to a continuous loop of updates if state is being updated.
function ExampleComponent(){
const [count, setCount] = useState(0);
useEffect(() => {
setCount((count) => count+1);
});
}
This happened because there isn't any dependency array specified, indicating that the effect
should be run every time after the component re-renders.
2/8
function ExampleComponent(){
const [count, setCount] = useState(0);
useEffect(() => {
setCount((count) => count+1);
}, []);
}
This will ensure that the effect is only executed after the initial rendering of the component.
function ExampleComponent(){
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
// logic
}), [isLoggedIn];
}
That way, the effect is only run initially and when the dependency has changed after the
component has re-rendered.
Primitive values are basic data types such as Strings, Booleans, Numbers, Null and
Undefined.
On the other hand, reference values are more complex data types such as Arrays and
Objects.
3/8
Types of primitive and reference values in JavaScript
When a reference value is assigned to a variable, the value and location to that value is
stored and the variable will only point to that location.
Whereas with a primitive value, the variable is directly assigned to the primitive's value. The
value is stored on a stack, a data structure used to store static data.
With reference values such as Functions and Objects, they are stored in a heap, a data
structure used for dynamic memory allocation, which is useful when storing complex data
types.
The variable is then assigned to the location in the stack, which points to the reference value
in the heap.
4/8
A Heap is a data structure used to store reference values
This is helps make our applications more efficient. Imagine having to create a duplicate of a
complex object every time it is re-assigned to a new variable! Instead, the new variable can
just point to the same location in the heap.
As useful as it is, reference values can be problematic when used as a dependency. This is
because React will compare the location of the reference value if it is used as a dependency
instead of the value's contents.
function ExampleComponent(props){
const [count, setCount] = useState(1);
let data = {
a: 1,
b: 2
};
useEffect(() => {
setCount((count) => count+1);
//other logic
}, [data]);
}
5/8
When the component is re-rendered, a new data object is created, so its reference
location is different from the previous
This causes the effect to run again since the dependency data object has changed
The cycle repeats, causing an infinite loop
To prevent this from happening, we can use the useRef hook. It allows us to re-use the same
value between re-renders.
This hook allows us to store values that will persist between renders, so the object's
reference location will be the same throughout all render cycles.
function ExampleComponent(props){
const [count, setCount] = useState(1);
const data = useRef({
a: 1,
b: 2,
});
useEffect(() => {
setCount((count) => count+1);
// logic
}, [data.current]);
// rest of component
}
The useRef hook takes in an initial value and returns a single object with a property called
current.
The current property will be the value passed into the useRef hook, and will be the same
throughout all renders of the component.
This ensures the effect doesn't run in an infinite loop since the dependency in the useEffect
hook will no longer change with each render of the component.
Note that you can also change the value of the data.current property. For example:
data.current = {c: 3, d: 4}
By changing the value of data.current, it will not trigger the component to re-render and
React is not aware of this change.
6/8
Since a function is a reference value in JavaScript, we encounter the same issue with using
objects as dependencies.
For example, if we have a function in our component, the function will be re-created every
time the component is re-rendered:
function ExampleComponent(props){
const [count, setCount] = useState(1);
const submitForm = (event) => {
// logic
};
useEffect(() => {
setCount((count) => count+1);
// logic
}, [submitForm]);
// rest of component
}
To avoid the function from being re-created every time the component is re-rendered, we can
use the useCallback hook:
function ExampleComponent(props){
const [count, setCount] = useState(1);
const submitForm = useCallback((event) => {
// logic
}, []);
useEffect(() => {
setCount((count) => count++);
// logic
}, [submitForm]);
// rest of component
}
The useCallback hook also accepts two arguments, the first being the function that needs to
be cached and stored without changing between renders, and the second being a
dependency array. If the dependencies in the useCallback hook changes, the function is re-
created.
7/8
So, similar to using useEffect, we can use an empty dependency array to ensure the
function isn't being re-created between renders.
This prevents the effect from running in an infinite loop when a function is used as a
dependency.
Summary
The useEffect hook in React is necessary when working with side effects in your React
components. But even with experience, common mistakes can lead to infinite loops in your
components. Be sure to watch out for missing dependencies, and using references or
functions as dependencies when that happens.
We also took a look at how to use the useRef and useCallback hooks to prevent objects
from being re-created in between renders.
If you enjoy my writing, consider checking out my YouTube channel for more.
Happy coding!
👋
Roy Chng
Hey , I write articles about Python and Frontend technologies!
Learn to code for free. freeCodeCamp's open source curriculum has helped more than
40,000 people get jobs as developers. Get started
8/8