π£ React useEffect
Hook β Lifecycle Logic in Functional Components (2025 Guide)
π§² Introduction β Why useEffect
Is a Game-Changer
Before Hooks, lifecycle logic in React required class components using methods like componentDidMount
, componentDidUpdate
, and componentWillUnmount
. With useEffect
, all these can be handled within functional components β making the code more readable, modular, and side-effect-friendly.
π― In this guide, youβll learn:
- What
useEffect
is and how it works - How to replicate lifecycle behavior (mount/update/unmount)
- How to use cleanup functions
- Real-world examples like data fetching and subscriptions
π§© What is useEffect
?
useEffect
is a React Hook that runs side effects in functional components. Side effects include:
- Data fetching
- Subscribing to events
- Manual DOM manipulations
- Logging
- Timers
β Basic Syntax:
useEffect(() => {
// side effect logic
}, [dependencies]);
π 1. Mimic Lifecycle Methods
Class Lifecycle | Equivalent useEffect Usage |
---|---|
componentDidMount | useEffect(() => {}, []) |
componentDidUpdate | useEffect(() => {}, [dependency]) |
componentWillUnmount | useEffect(() => return cleanup, []) |
π¦ 2. Mount-Only Logic (componentDidMount
)
β Example:
useEffect(() => {
console.log('Component mounted');
}, []);
β
Runs once, after initial render
β
Useful for API calls, analytics, or setup logic
π 3. Respond to Updates (componentDidUpdate
)
Run effects when certain values change.
β Example:
useEffect(() => {
console.log(`Count updated to ${count}`);
}, [count]);
β
Triggers only when count
changes
π« 4. Cleanup on Unmount (componentWillUnmount
)
Use cleanup functions to remove subscriptions, listeners, or intervals.
β Example:
useEffect(() => {
const interval = setInterval(() => {
console.log('Running...');
}, 1000);
return () => {
clearInterval(interval);
console.log('Component unmounted');
};
}, []);
β
Prevents memory leaks
β
Runs once when the component is removed
π 5. Fetch Data with useEffect
β API Call on Mount:
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(data => setData(data));
}, []);
β Works great with async/await (via IIFE):
useEffect(() => {
(async () => {
const res = await fetch('/api/data');
const json = await res.json();
setData(json);
})();
}, []);
π§© 6. useEffect Dependencies β How It Works
- Empty array
[]
β run once on mount - No array β run on every render
- With
[dep1, dep2]
β run when any listed dep changes
β οΈ Always Declare Dependencies:
useEffect(() => {
document.title = `${count} clicks`;
}, [count]);
β Missing deps may cause stale values or bugs
β οΈ 7. Common Pitfalls & Fixes
Issue | Solution |
---|---|
Infinite loops | Add correct dependencies |
Stale closure values | Use state inside effect or updater func |
Skipped cleanup | Always return a cleanup function if needed |
Async directly in useEffect | Wrap in IIFE or move logic outside |
π Best Practices
β
Keep effect logic focused and clean
β
Use multiple useEffect()
calls for different concerns
β
Use cleanup to avoid memory leaks
β
Use eslint-plugin-react-hooks
to catch dependency errors
β
Avoid unnecessary re-renders with correct dependency arrays
π Summary β Recap & Next Steps
The useEffect
hook unlocks the full power of side effects and lifecycle logic inside React functional components. Whether youβre fetching data, syncing state, or cleaning up timers, useEffect
is your go-to tool.
π Key Takeaways:
useEffect
runs after render and controls side effects- Empty array
[]
means run once (mount) - Use cleanup for unmount logic
- Keep dependencies accurate to avoid bugs
- Combine with
useState
for dynamic, interactive UIs
βοΈ Real-World Relevance:
From data dashboards to chat apps and search filters, useEffect
is used in almost every React component in platforms like YouTube, Zoom, and Stripe.
β FAQ Section
β Can I use async/await directly inside useEffect
?
β No. Instead, define and invoke an async function inside:
useEffect(() => {
(async () => {
await fetchData();
})();
}, []);
β What happens if I forget the dependency array?
β
The effect will run on every render, possibly causing performance issues or infinite loops.
β Can I have multiple useEffect()
hooks?
β
Yes! Itβs best to separate concerns:
useEffect(() => { /* fetch */ }, []);
useEffect(() => { /* timer */ }, []);
β How do I clean up a subscription or timer?
β
Return a cleanup function:
useEffect(() => {
const id = setInterval(...);
return () => clearInterval(id);
}, []);
β Is useEffect
called before or after rendering?
β
It runs after the DOM has been painted (post-render).
Share Now :