Code To Learn logo

Code To Learn

M3: Effects & Data

L10: M3 Challenge

Build a complete listings page with pagination, caching, and advanced features

Time to put everything you've learned to the test! In this comprehensive challenge, you'll build an advanced listings page with pagination, caching, refresh functionality, and optional bonus features.

Challenge Overview

Objective: Build a fully-featured listings page that demonstrates mastery of useEffect, async data, state management, and custom hooks.

Time Estimate: 2-3 hours

Difficulty: ⭐⭐⭐ Intermediate to Advanced

Requirements

Required Features (Core Challenge)

You must implement these three features:

Pagination

  • Display 6 listings per page
  • Show current page and total pages
  • "Previous" and "Next" buttons
  • Disable buttons at boundaries (first/last page)
  • Fetch only the listings for the current page

Refresh Button

  • Manual refresh button to reload data
  • Show loading state during refresh
  • Properly cancel ongoing requests when refreshing
  • Display success feedback after refresh

Response Caching

  • Cache API responses by page number
  • Don't re-fetch already loaded pages
  • Clear cache on refresh
  • Implement cache expiration (5 minutes)

Bonus Features (Optional)

Challenge yourself with these advanced features:

  1. Infinite Scroll - Load next page automatically when scrolling to bottom
  2. Search Debouncing - Implement search with 500ms delay
  3. Optimistic Updates - Show immediate feedback before API responds
  4. Loading Skeletons - Animated placeholder content instead of spinner
  5. Error Recovery - Automatic retry with exponential backoff

Getting Started

Review Your Current Code

Take a look at your current HomePage.jsx. You should have:

  • Data fetching with useEffect
  • Loading and error states
  • Display of listings in a grid

Plan Your Approach

Before coding, think through:

  1. State management: What state variables do you need?

    • currentPage, totalPages, cache, isRefreshing, etc.
  2. API updates: How will you modify the mock API?

    • Add pagination support: getAllListings(page, perPage)
    • Return metadata: { listings, total, page, perPage }
  3. Custom hooks: Should you extract any logic?

    • usePaginatedListings?
    • useCachedData?

Set Up Your Workspace

Make sure you have:

  • Clean component state (commit or save current work)
  • Mock API ready to modify
  • React DevTools open for debugging

Part 1: Implement Pagination

Let's start with pagination - the foundation of this challenge.

Part 2: Add Refresh Functionality

Now implement a manual refresh button that properly handles cleanup.

Part 3: Implement Response Caching

The most challenging part! Cache responses to avoid redundant API calls.

Bonus Challenge 1: Infinite Scroll

Bonus Challenge 2: Search with Debouncing

Bonus Challenge 3: Loading Skeletons

Testing Your Solution

Functionality Testing

Test each feature:

  1. Pagination

    • Navigate between pages
    • Check that listings change
    • Verify buttons disable at boundaries
    • Check page counter updates correctly
  2. Refresh

    • Click refresh button
    • Verify loading state shows
    • Check that data reloads
    • Test refresh while on different pages
  3. Caching

    • Go to page 2, then back to page 1
    • Should load instantly from cache
    • Wait 5+ minutes, should re-fetch
    • Refresh should clear cache

Edge Cases

Test these scenarios:

  • Refresh while already loading
  • Navigate quickly between pages
  • Refresh on last page
  • Empty search results
  • Network errors during refresh

Performance Check

Use React DevTools:

  • No unnecessary re-renders
  • Cleanup functions running properly
  • No memory leaks (check intervals/listeners)
  • Proper AbortController usage

Complete Solution

Try It Yourself First!

Don't peek at the solution until you've attempted the challenge! Learning happens through struggle. If you're stuck, review the hints in each section first.

Code Quality Checklist

Before submitting, verify:

  • No console errors - Clean console output
  • Proper cleanup - All intervals/listeners cleaned up
  • Loading states - User always sees feedback
  • Error handling - All errors caught and displayed
  • AbortController - Requests properly cancelled
  • Cache expiration - Old cache cleared after 5 minutes
  • Accessible UI - Buttons have proper aria-labels
  • Responsive design - Works on mobile/tablet/desktop
  • Code organization - Logic extracted to custom hooks
  • Comments - Complex logic is documented

Reflection Questions

After completing the challenge, consider:

  1. What was the most challenging part? Why?
  2. How did custom hooks improve your code? What would it look like without them?
  3. What edge cases did you discover? How did you handle them?
  4. How would you test this code? What unit tests would you write?
  5. What performance improvements could you make? React.memo? useMemo?

Congratulations!

You've completed Module 3! You now have practical experience with:

  • ✅ Complex state management
  • ✅ Advanced useEffect patterns
  • ✅ Custom hooks for reusability
  • ✅ Caching and performance optimization
  • ✅ Real-world async data handling

These skills form the foundation for building production-ready React applications!

What's Next?

Continue your React journey with Module 4: React Router:

  • Learn client-side routing
  • Build multi-page applications
  • Handle dynamic routes and parameters
  • Implement navigation and route protection

You're ready for the next level! 🚀