Welcome to Part 4 where we’ll unlock the power of side effects and dynamic UI rendering. These concepts will take your React skills to the professional level!
The useEffect Hook Explained
useEffect handles side effects in functional components – operations that interact with the outside world.
import { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(json => {
setData(json);
setLoading(false);
});
}, []); // Empty dependency array = runs once
return (
<div>
{loading ? <p>Loading...</p> : <pre>{JSON.stringify(data)}</pre>}
</div>
);
}
useEffect Dependency Cheat Sheet
| Dependency Array | Behavior |
|---|---|
[] | Runs once after initial render |
[state] | Runs when state changes |
| None | Runs after every render |
Cleanup Function Example
useEffect(() => {
const timer = setInterval(() => {
console.log('Timer tick');
}, 1000);
return () => clearInterval(timer); // Cleanup
}, []);
Conditional Rendering Techniques
1. Ternary Operator
{isLoggedIn ? (
<Dashboard />
) : (
<LoginForm />
)}
2. Logical && Operator
{hasNotifications && (
<div className="badge">{notificationCount}</div>
)}
3. Component Variables
function UserGreeting() {
let content;
if (user) {
content = <h1>Welcome back!</h1>;
} else {
content = <h1>Please sign up.</h1>;
}
return <div>{content}</div>;
}
Practical Example: API Dashboard
function ApiDashboard() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [retryCount, setRetryCount] = useState(0);
useEffect(() => {
const controller = new AbortController();
setLoading(true);
fetch(`https://api.example.com/data?retry=${retryCount}`, {
signal: controller.signal
})
.then(response => {
if (!response.ok) throw new Error('Network error');
return response.json();
})
.then(json => {
setData(json);
setError(null);
})
.catch(err => {
if (err.name !== 'AbortError') {
setError(err.message);
}
})
.finally(() => setLoading(false));
return () => controller.abort();
}, [retryCount]);
return (
<div className="dashboard">
{loading && <div className="loader">Loading...</div>}
{error && (
<div className="error">
<p>{error}</p>
<button onClick={() => setRetryCount(c => c + 1)}>
Retry
</button>
</div>
)}
{data && (
<div className="data-display">
<h2>{data.title}</h2>
<p>{data.description}</p>
</div>
)}
</div>
);
}
Key Features in This Example:
- Fetch cancellation with
AbortController - Loading/error/data states
- Retry mechanism
- Conditional rendering patterns
Performance Optimization
1. Memoization with useMemo
const processedData = useMemo(() => {
return largeArray.filter(item => item.active)
.sort((a, b) => a.value - b.value);
}, [largeArray]); // Only recalculates when largeArray changes
2. Callback Optimization with useCallback
const handleClick = useCallback(() => {
console.log('Item clicked:', itemId);
}, [itemId]); // Only recreates when itemId changes
What’s Next?
In Part 5, we’ll explore:
✅ Custom hooks for reusable logic
✅ Context API for state management
✅ React Router for navigation
Exercise for You
Create a useWindowSize custom hook that tracks browser window dimensions and updates components when resized. Use it in a component that displays “Mobile View” or “Desktop View” based on width.
Enjoyed this tutorial? Subscribe for Part 5! 🚀
Questions? Ask in the comments below!
Series Navigation:
🔹 Part 1: Introduction to React
🔹 Part 2: JSX, Components & Props
🔹 Part 3: State and Events
🔹 Part 4: useEffect & Conditional Rendering (You’re here)
🔹 Part 5: Custom Hooks & Context API
