Let's think about this for a second
This lesson is a step harder than Part 1, combining concepts you learned in the Intermediate/Advanced chapter — useEffect, useContext, custom hooks, data fetching, and React Router. Each task is meant to give you hands-on practice with patterns you'll run into all the time in real-world apps: pulling data from an API, sharing a theme across an entire app, extracting logic into a custom hook, and reading a URL param when navigating between pages. As you work through these tasks yourself, you'll also get to review how to combine them with the concepts from the Basic chapter.
Practice Exercises
Task 1: Use useEffect to fetch the user list from fetch("https://jsonplaceholder.typicode.com/users") and render it along with a loading state. Task 2: Build a ThemeContext (light/dark) with createContext, and wire it up so two levels of nested components can read the theme value with useContext. Task 3: Build a custom hook called useToggle(initialValue) that returns a value and a toggle function (so it can be used for things like opening/closing a modal or showing/hiding a sidebar). Task 4: Use react-router-dom to set up a /users/:id route, read the id with useParams, and display it on screen.
Code Example
// Task 1 starter - UserList.jsx
import { useState, useEffect } from "react";
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
// TODO: fetch users inside useEffect, then setUsers + setLoading(false)
if (loading) return <p>Loading...</p>;
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
export default UserList;
// Task 3 starter - useToggle.js
import { useState } from "react";
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
// TODO: return [value, toggle] where toggle flips the boolean
}
export default useToggle;
// Task 4 starter - UserDetail.jsx (used at route /users/:id)
import { useParams } from "react-router-dom";
function UserDetail() {
// TODO: read id with useParams and display it
return <h3>User Detail</h3>;
}
export default UserDetail;Once all 4 tasks are done: a user list appears from API data, the theme context reaches down to nested components, the toggle hook is shared between 2 components, and the user detail changes based on the URL param.Try it in 5 minutes
Add an error state to Task 1's UserList — show a "Failed to load users" message if the fetch fails (call setError(true) inside the catch block) — this should only take about 5 minutes.
A quick word of caution
Instead of using an async function directly inside useEffect, you need to define a separate async function inside it and call it immediately (the IIFE pattern) — you'll use this a lot with fetch APIs.