React.js + Next.js · Module 3. Forms and Effects · Lesson 15 · Point 15
Multiple useEffect Hooks in React
React + TypeScript · GoIT Dev Notes
This lesson explains how one component can use several Effects, how each Effect responds to its own dependencies, and how rendering differs from external synchronization.
You will work with separate states, shared dependency arrays, document titles, console logging, derived values, StrictMode, and the exhaustive-dependencies rule.
REACT · 01
1. What Is useEffect?
The useEffect Hook lets a component synchronize with an external system such as a browser API, timer, network connection, or third-party widget.
Effects run after React commits the relevant changes to the DOM.
import { useEffect } from "react";
export default function App() {
useEffect(function () {
console.log("Component mounted!");
}, []);
return <h1>Hello React!</h1>;
}
Browser Result
The empty dependency array means the Effect is associated with mounting. In development, StrictMode may run an additional setup and cleanup cycle to reveal bugs.
REACT · 02
2. Multiple useEffect Hooks
A component can contain several useEffect calls. Each Effect has its own setup function, optional cleanup, purpose, and dependency array.
import { useEffect } from "react";
export default function App() {
useEffect(function () {
console.log("First effect");
}, []);
useEffect(function () {
console.log("Second effect");
}, []);
return <h1>Hello Nikita!</h1>;
}
Browser Result
Although both run after the component mounts, they are separate Effects and should represent separate synchronization processes.
REACT · 03
3. Three Common Dependency Patterns
| Syntax | When setup runs |
|---|---|
useEffect(setup, []) | After mounting |
useEffect(setup, [count]) | After mounting and when count changes |
useEffect(setup) | After every committed render |
import { useEffect, useState } from "react";
export default function App() {
const [clicks, setClicks] = useState(0);
useEffect(function () {
console.log("Component mounted!");
}, []);
useEffect(function () {
console.log("Clicks updated:", clicks);
}, [clicks]);
useEffect(function () {
document.title = `You clicked ${clicks} times`;
});
return (
<button onClick={function () { setClicks(clicks + 1); }}>
You clicked {clicks} times
</button>
);
}
Browser Result
The no-array form is valid, but it is broader than necessary here. If an Effect only uses clicks, [clicks] usually communicates the intended synchronization more precisely.
REACT · 04
4. Rendering vs. Re-rendering
Rendering means React calls a component function to calculate its JSX. Re-rendering means React calls it again, usually after state or props change.
export default function App() {
console.log("Rendering!");
return <h1>Hello!</h1>;
}
Browser Result
- React calls the component function.
- The component calculates JSX.
- React commits any necessary DOM changes.
- React runs the relevant Effects.
A render does not guarantee a visible DOM change. React may calculate the same output as before.
REACT · 05
5. Separate Effects for Separate States
import { useEffect, useState } from "react";
export default function App() {
const [first, setFirst] = useState(0);
const [second, setSecond] = useState(0);
useEffect(function () {
console.log("First updated:", first);
}, [first]);
useEffect(function () {
console.log("Second updated:", second);
}, [second]);
return (
<div>
<button onClick={function () { setFirst(first + 1); }}>
First: {first}
</button>
<button onClick={function () { setSecond(second + 1); }}>
Second: {second}
</button>
</div>
);
}
Browser Result
first re-renders the component, but only the Effect whose dependency changed runs again.REACT · 06
6. One Effect with Multiple Dependencies
useEffect(function () {
console.log("First or second updated:", first + second);
}, [first, second]);
React compares every dependency with its previous value using Object.is. The Effect runs after mounting and again whenever either value changes.
| Action | first | second | Logged total |
|---|---|---|---|
| Initial commit | 0 | 0 | 0 |
| Click First | 1 | 0 | 1 |
| Click Second | 1 | 1 | 2 |
| Click First | 2 | 1 | 3 |
Use one Effect with several dependencies when one synchronization process genuinely depends on all of those values.
REACT · 07
7. Complete Example: Three Effects and Two Counters
import { useEffect, useState } from "react";
export default function App() {
const [first, setFirst] = useState<number>(0);
const [second, setSecond] = useState<number>(0);
useEffect(function () {
console.log("First updated:", first);
}, [first]);
useEffect(function () {
console.log("Second updated:", second);
}, [second]);
useEffect(function () {
console.log("Total:", first + second);
}, [first, second]);
function resetCounters() {
setFirst(0);
setSecond(0);
}
return (
<div>
<h1>Multiple useEffect Example</h1>
<button onClick={function () { setFirst(first + 1); }}>
First: {first}
</button>
<button onClick={function () { setSecond(second + 1); }}>
Second: {second}
</button>
<p>Total: {first + second}</p>
<button onClick={resetCounters}>Reset counters</button>
</div>
);
}
Browser Result
The total displayed in JSX is derived directly during rendering. The shared Effect exists only to demonstrate synchronization when either counter changes.
REACT · 08
8. Always Specify Correct Dependencies
An Effect should declare every reactive value it reads. Reactive values include props and values declared inside the component, including state.
Incorrect
useEffect(function () {
console.log(clicks);
}, []); // Missing clicks
The Effect reads clicks but promises never to synchronize again. The React Hooks ESLint rule should report the missing dependency.
Correct
useEffect(function () {
console.log(clicks);
}, [clicks]);
Do not remove dependencies merely to suppress repeated execution. If an Effect runs too often, reconsider whether the Effect is needed, split its responsibilities, or stabilize the values involved.
REACT · 09
9. Why Separate Effects?
Separate Effects are useful when a component synchronizes with different external systems.
useEffect(function () {
document.title = `Clicks: ${clicks}`;
}, [clicks]);
useEffect(function () {
console.log("User changed:", username);
}, [username]);
The first Effect synchronizes the browser title. The second performs separate logging. Their purposes and dependencies are different.
Do Not Use an Effect for Ordinary Calculations
const total = first + second;
A total derived from current state can be calculated during rendering. It does not need another state variable or Effect because no external system is involved.
REACT · 10
10. Important Rules
- A component can use multiple
useEffectHooks. - Each Effect has its own setup, optional cleanup, and dependency list.
- Effects run after React commits changes.
- An empty array associates an Effect with mounting and unmounting.
- A dependency list reruns the Effect when one of its values changes.
- Omitting the dependency array runs the Effect after every committed render.
- One Effect can depend on several reactive values.
- Declare every reactive dependency used by the Effect.
- Separate Effects that synchronize with different external systems.
- Calculate ordinary derived values during rendering.
- Expect additional development checks under StrictMode.
Main idea: use several Effects when a component has several independent synchronization processes. Give each one the dependencies that describe exactly when it must reconnect or update.