React useEffect Patterns for Reliable Side Effects
π§ useEffect Cheat Sheet (Beginner β Confident)
1οΈβ£ What is useEffect? (Plain English)
useEffect lets you run side effects in a React component.
π Side effects = things that are not UI rendering.
- Fetching data
- Calling APIs
- Using
localStorage - Timers (
setTimeout,setInterval) - Event listeners
- Updating the document title
Rule of thumb:
If it touches the outside world, it belongs inuseEffect.
2οΈβ£ Basic Syntax (Memorize This)
useEffect(() => {
// side effect code
}, [dependencies]);
π Two parts:
- Effect function β what to run
- Dependency array β when to run
3οΈβ£ The 3 Most Important Patterns (MUST KNOW)
β 1. Run once (on component mount)
useEffect(() => {
console.log("Component mounted");
}, []);
π§ Think:
βRun this once when the component appears.β
π Common use cases:
- API calls
- Initial setup
- Fetching data
β 2. Run when something changes
useEffect(() => {
console.log("Count changed:", count);
}, [count]);
π§ Think:
βWhenever
countchanges, run this.β
π Use cases:
- Re-fetching data
- Syncing state
- Updating the document title
β 3. Run on every render (rare & dangerous)
useEffect(() => {
console.log("Runs every render");
});
β οΈ Avoid unless you really know why β this runs after every render.
4οΈβ£ Real Examples (Very Important)
πΉ Change document title
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
β Runs only when count changes.
πΉ Fetching data from API
useEffect(() => {
fetch("https://api.example.com/users")
.then(res => res.json())
.then(data => setUsers(data));
}, []);
β Fetches once when the component mounts.
πΉ Using localStorage
useEffect(() => {
localStorage.setItem("name", name);
}, [name]);
β Syncs state with browser storage.
5οΈβ£ Cleanup Function (VERY IMPORTANT)
Some effects must be cleaned up or bugs and leaks can happen.
Syntax
useEffect(() => {
return () => {
// cleanup code
};
}, []);
πΉ Example: Event listener
useEffect(() => {
const handleResize = () => {
console.log(window.innerWidth);
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
π§ Think:
βClean up before the component unmounts.β
πΉ Example: setInterval
useEffect(() => {
const id = setInterval(() => {
console.log("Tick");
}, 1000);
return () => clearInterval(id);
}, []);
6οΈβ£ Dependency Array β How to Think
Rule
π Everything you use inside useEffect that comes from outside the effect should go in the dependency array.
Example
useEffect(() => {
console.log(name, age);
}, [name, age]);
β Wrong
useEffect(() => {
console.log(name);
}, []); // β name used but not listed
This causes stale values.
7οΈβ£ Infinite Loop Problem (Common Beginner Mistake)
β Wrong
useEffect(() => {
setCount(count + 1);
}, [count]);
π The effect updates count β count triggers the effect again β π₯ infinite loop.
β Fix using functional update
useEffect(() => {
setCount(c => c + 1);
}, []);
8οΈβ£ Multiple useEffects (Best Practice)
Prefer multiple small, focused effects over one large effect.
// One big effect (less ideal)
useEffect(() => {
fetchData();
updateTitle();
addListener();
}, []);
// Better: multiple focused effects
useEffect(fetchData, []);
useEffect(updateTitle, [count]);
useEffect(addListener, []);
π§ Cleaner and easier to debug.
9οΈβ£ When NOT to Use useEffect
β Don’t use useEffect for things that belong in render or derived values:
- Updating state directly from props
- Simple calculations
- Rendering logic
π Do this instead:
const total = price * quantity;
If it can be done during render β do not use useEffect.
π Mental Model (Remember This Forever)
Render = describe UI
useEffect = sync with outside world
π₯ Common Mistakes Checklist
- β Forgetting the dependency array
- β Updating state without cleanup
- β Using
useEffectfor simple calculations - β Causing infinite loops
- β Ignoring cleanup functions
π§ͺ Tiny Practice Snippet
useEffect(() => {
console.log("Hello React");
}, []);
Ask yourself:
- When does it run? β once
- Why? β empty dependency array
