L9: M3 Review
Comprehensive review of useEffect, side effects, and async data patterns
Congratulations on completing Module 3! Let's review everything you've learned about useEffect, side effects, and handling asynchronous data in React.
What You've Learned
Over the past 8 lessons, you've mastered:
Core Concepts
- ✅ useEffect hook - Running side effects in functional components
- ✅ Dependency arrays - Controlling when effects run
- ✅ Async/await - Handling asynchronous operations in React
- ✅ Data fetching - Loading data from APIs
- ✅ Loading states - Showing feedback during async operations
- ✅ Error handling - Gracefully handling failures
- ✅ Cleanup functions - Preventing memory leaks and race conditions
- ✅ Custom hooks - Extracting and reusing logic
Practical Skills
- Built a mock API for development
- Implemented data fetching with proper state management
- Created reusable UI components (Spinner, ErrorMessage, ImageCarousel)
- Handled edge cases and error scenarios
- Used AbortController for request cancellation
- Refactored complex components with custom hooks
useEffect Patterns Quick Reference
Common useEffect Pitfalls
Learn from these common mistakes!
When to Use useEffect
✅ Use useEffect for:
-
Data fetching
useEffect(() => { fetchData(); }, []); -
Subscriptions
useEffect(() => { const sub = api.subscribe(callback); return () => sub.unsubscribe(); }, []); -
Timers
useEffect(() => { const id = setTimeout(doSomething, 1000); return () => clearTimeout(id); }, []); -
DOM manipulation
useEffect(() => { document.title = `Page: ${page}`; }, [page]); -
Event listeners
useEffect(() => { window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); -
Syncing with external systems
useEffect(() => { map.setCenter(coordinates); }, [coordinates]);
❌ DON'T use useEffect for:
-
Derived state (calculate during render)
// ❌ Don't useEffect(() => { setTotal(price * quantity); }, [price, quantity]); // ✅ Do const total = price * quantity; -
Event handlers (use event handler functions)
// ❌ Don't useEffect(() => { if (clicked) handleClick(); }, [clicked]); // ✅ Do <button onClick={handleClick}>Click</button> -
Transforming data for render (transform during render)
// ❌ Don't useEffect(() => { setFilteredUsers(users.filter(u => u.active)); }, [users]); // ✅ Do const filteredUsers = users.filter(u => u.active); -
Initializing state (use default state or useMemo)
// ❌ Don't useEffect(() => { setInitialData(expensiveComputation()); }, []); // ✅ Do const [data] = useState(() => expensiveComputation());
Best Practices Summary
useEffect Best Practices
- Always specify dependencies - Include every value used in the effect
- Always clean up - Return cleanup function for timers, subscriptions, requests
- Use functional updates - Use
setState(prev => ...)for state in dependencies - Keep effects focused - One effect per concern, split complex effects
- Handle loading/error states - Always show feedback to users
- Cancel requests - Use AbortController for fetch requests
- Avoid race conditions - Use cleanup flags or AbortController
- Consider custom hooks - Extract reusable logic into custom hooks
Data Fetching Pattern Checklist
When implementing data fetching, make sure you:
- ✅ Use
useEffectwith empty array for initial fetch - ✅ Add
isLoadingstate that starts astrue - ✅ Add
errorstate for error handling - ✅ Wrap fetch in async function inside effect
- ✅ Use
try/catch/finallyfor proper error handling - ✅ Set
isLoading = falseinfinallyblock - ✅ Clear previous errors before new fetch
- ✅ Add cleanup function with AbortController
- ✅ Check for AbortError in catch block
- ✅ Show loading UI while fetching
- ✅ Show error UI with retry option if failed
- ✅ Handle empty results gracefully
Module 3 Component Architecture
Here's how the components we built fit together:
HomePage
├── Spinner (loading state)
├── ErrorMessage (error state)
└── PropertyCard (for each listing)
└── ImageCarousel (image display)
├── Navigation buttons
└── Slide indicators
Custom Hooks
├── useFetchListings (data fetching logic)
└── useFilteredListings (filtering logic)
API Layer
└── mockApi.js
├── getAllListings()
├── getListingById()
├── searchListings()
└── filterListings()Self-Assessment Quiz
Test your understanding! Try to answer these before expanding:
What You Can Build Now
With Module 3 complete, you can build:
- 📱 Data-driven applications with API fetching
- 🎨 Interactive components with timers and animations
- 🔄 Auto-updating UIs with subscriptions
- 🎠 Image carousels and sliders
- 🔍 Search interfaces with debouncing
- 📊 Dashboards with real-time data
- 🎯 Forms with validation and async submission
Preview: Module 4 - React Router
In the next module, you'll learn:
- Client-side routing - Building multi-page SPAs
- Route parameters - Dynamic URLs like
/listing/:id - Nested routes - Complex page layouts
- Navigation - Links, redirects, and programmatic navigation
- Route protection - Authentication and guards
- Data loading - Fetching data based on routes
Get ready to build a complete multi-page booking application!
You've Mastered useEffect!
You now understand:
- How side effects work in React
- When and how to use useEffect
- How to handle async data properly
- How to prevent common bugs (race conditions, memory leaks)
- How to write clean, reusable code with custom hooks
Take the Module Challenge next to solidify these skills!
What's Next?
Ready to test your knowledge? The Module 3 Challenge awaits!
You'll build a complete feature that combines everything from this module:
- Data fetching with loading and error states
- Pagination for browsing listings
- Refresh button with proper cleanup
- Response caching to reduce API calls
- Bonus challenges: infinite scroll, search debouncing, optimistic updates
This is your chance to prove you've mastered React effects and async data!