React Interview: Why those useEffect hooks are not working as expected?
Interview: Why those useEffect hooks are not working as expected?
import { useState, useEffect } from "react";
export default function App() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setCount1(count1 => count1 + 1);
}, 1000);
return () => clearInterval(intervalId);
});
useEffect(() => {
const intervalId = setInterval(() => {
setCount2(count2 => count2 + 1);
}, 3000);
return () => clearInterval(intervalId);
});
return (
<div className="App">
<p>Counter 1: {count1}</p>
<p>Counter 2: {count2}</p>
</div>
);
}
Expected result
In this functional component I’m creating two counters, each one increments at different intervals.
- It initializes two more state variables
count1
andcount2
. Both are initially set to 0. These variables will store the values of the two counters. - It uses two
useEffect
hooks. They set up intervals to update the counters at specified intervals. - The first
useEffect
sets up an interval forcount1
to increment every 1 second (1000 milliseconds). It also returns a cleanup function that clears the interval when thisuseEffect
is unmounted or when the component is re-rendered. - The second
useEffect
does the same forcount2
, but it increments it every 3 seconds (3000 milliseconds). - The
return
statement defines the JSX that will be rendered on the web page. It displays the current values ofcount1
andcount2
.
So expected result is to see something like this:
However, it’s working in this way:
Why it is not working?
The issue with the second counter not updating as expected is due to the lack of specifying a dependency array in the useEffect
hooks.
- During the initial render, the component is displayed with both
count1
andcount2
set to 0. - After the initial render, the
useEffect
hooks are executed. - The first counter (
count1
) has a shorter interval and updates every 1 second, callingsetCount1
. This causes the component to re-render with the new value ofcount1
(which is 1) after 1 second. - As a result of the re-render, the cleanup functions of both
useEffect
hooks are called, clearing both intervals. - In the next render,
count1
has a value of 1, butcount2
is still at 0. - The
useEffect
hooks run again. - The first counter once again calls
setCount1
after 1 second to incrementcount1
. This re-renders the component withcount1
value of 2. - However, the cleanup functions are called again for both
useEffect
hooks, preventing the second counter from updatingcount2
.
Conclusion
In React’s useEffect
hook, specifying a dependency array is not always required, but it can be crucial for controlling when the effect runs and ensuring that your component behaves as expected or if it is running infinite loop.