Effect Separation: One Effect per Concern
Split effects so each handles a single job with its own dependencies.
Introduction
Effect separation is about giving each useEffect a single responsibility. Instead of one big effect doing multiple things, you split them so each has a clear purpose and its own dependency list.
Why this matters
Bundling unrelated work into one useEffect ties their lifecycles together and leads to confusing dependency arrays. Separate effects make intent clear and avoid accidental re‑runs.
The problem
A single effect updates the document title and logs count changes, so both concerns re-run whenever either dependency changes.
Inefficient approach
Mixed concerns and coupled dependencies:
import { useState, useEffect } from "react";
function App() {
const [name, setName] = useState("John");
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Hello ${name}`;
console.log(`Count changed to: ${count}`);
}, [name, count]);
return (
<div>
<h1>Effect Separation Pattern</h1>
<div>
<label>
Name:{" "}
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
</div>
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
</div>
);
}
export default App;
The solution
One effect updates the title; another logs count changes.
import { useState, useEffect } from "react";
function App() {
const [name, setName] = useState("John");
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Hello ${name}`;
}, [name]);
useEffect(() => {
console.log(`Count changed to: ${count}`);
}, [count]);
return (
<div>
<h1>Effect Separation Pattern</h1>
<div>
<label>
Name:{" "}
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
</div>
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
</div>
);
}
export default App;
Step-by-step
-
Identify distinct concerns inside the combined effect.
-
Move each concern into its own
useEffect. -
Give each effect the minimal dependency array it needs.
-
Keep effect bodies small; extract helpers when logic grows.
Tips
-
Effects should be cohesive: one effect, one reason to re‑run.
-
Prefer deriving values or moving logic to event handlers when possible.
-
If an effect grows large, extract functions; keep the effect body small.
Knowledge base
Problem snippet:
useEffect(() => {
document.title = `Hello ${name}`;
console.log(`Count changed to: ${count}`);
}, [name, count]);
Solution snippet:
useEffect(() => { document.title = `Hello ${name}`; }, [name]);
useEffect(() => { console.log(`Count changed to: ${count}`); }, [count]);