React Best Practices
Learn hooks, state management, and modern patterns. Build components that scale.
0/12
Challenges Completed
0%
Progress
0
Your Total Score
1. The Infinite Re-render
A common React pitfall is causing infinite loops by creating new object references in the render body and passing them as dependencies to `useEffect`.
### Your Task:
- Fix the `UserProfile` component that is currently crashing the browser (simulated)
- The `fetchUser` function is being recreated on every render
- When passed to `useEffect`, it triggers another render, creating a loop
- Use `useCallback` or move the function inside the effect to fix it
2. The Memory Leak
Intervals and subscriptions must be cleaned up! If you don't return a cleanup function from `useEffect`, multiple intervals will pile up, causing performance issues and erratic behavior.
### Your Task:
- Fix the `Timer` component where the count speeds up every time you re-render
- The effect sets an interval but never clears it
- Return a cleanup function that calls `clearInterval`
3. Race Conditions
When fetching data asynchronously, requests can return out of order. If the user clicks 'Next' then 'Previous' quickly, the 'Next' request might finish *after* 'Previous', showing the wrong data.
### Your Task:
- Implement a 'stale' or 'cancelled' flag in the `useEffect`
- Create a boolean variable `ignore` set to false
- In the cleanup function, set `ignore` to true
- Only update state if `!ignore`
4. Stale Closures
Closures in JavaScript capture variables at the time they are created. In React, this means `setTimeout` or event listeners might see 'old' state values if you're not careful.
### Your Task:
- Fix the `DelayedLogger` component
- The user clicks 'Start Log' (count is 0), then clicks 'Increment' 5 times (count is 5)
- But when the log fires, it prints 'Count: 0'!
- Update the code to ensure it sees the *current* count, possibly using `useRef`
5. Expensive Calculations
Not everything needs to be memoized, but expensive calculations that run on every render definitely do.
### Your Task:
- Optimize the `PrimeFinder` component
- Finding the 1000th prime number is slow
- Currently, typing in the input field causes lag because `findNthPrime` runs on every keystroke
- Wrap the calculation in `useMemo` so it only runs when `n` changes
6. Unnecessary Re-renders
Passing new function references to optimized children breaks optimizations. `React.memo` only works if props remain stable.
### Your Task:
- The `ExpensiveChart` component is wrapped in `React.memo`, but it still re-renders whenever the parent updates
- This is because `handleResize` is a new function every time
- Wrap `handleResize` in `useCallback` to stabilize its reference
7. Derived State Anti-Pattern
A common mistake is syncing state with `useEffect`. If a value can be calculated from existing props or state, compute it during render! Don't put it in state.
### Your Task:
- Refactor `FullName` to remove the `fullName` state and the `useEffect`
- Calculate `fullName` directly in the component body
- This removes an unnecessary render pass and simplifies the code
8. Custom Hook: useDebounce
Debouncing is crucial for search inputs to avoid spamming your API. Let's encapsulate this logic in a reusable hook.
### Your Task:
- Implement `useDebounce(value, delay)`
- It should return a `debouncedValue` that only updates after the delay has passed without changes
- Use `useEffect` with a timeout and cleanup
- This allows the UI to update instantly (input value) while the API call waits (debounced value)
9. Context Optimization
Context providers that pass unstable objects cause ALL consumers to re-render, even if the data they need hasn't changed. This is a potential performance killer.
### Your Task:
- The `ThemeProvider` creates a new `{ theme, toggleTheme }` object every render
- Wrap this value in `useMemo` so it stays referentially stable
- This ensures that `Header`, which consumes context, only re-renders when the thread actually changes
10. Layout Shift Fix
`useEffect` runs *after* the browser paints. If you manipulate the DOM (like positioning a tooltip) inside it, the user might see a flicker or jump. `useLayoutEffect` runs *before* paint.
### Your Task:
- Fix the `Tooltip` component where the tooltip flickers briefly at (0,0) before jumping to the correct position
- Change `useEffect` to `useLayoutEffect` to block painting until the position is calculated
11. Compound Components
Compound components allow you to create expressive APIs like `<Toggle><Toggle.On>...</Toggle.On></Toggle>` where parent and children share state implicitly.
### Your Task:
- Create a `Toggle` component that uses `createContext` to share `isOn` and `toggle` state
- Create `Toggle.On` that only renders children if `isOn` is true
- Create `Toggle.Off` that only renders children if `isOn` is false
- Create `Toggle.Button` that triggers the toggle
12. Optimistic UI
Users expect instant feedback. Optimistic UI updates the interface *immediately* while the server request processes, reverting only if it fails.
### Your Task:
- Implement an optimistic 'Like' button
- When clicked, immediately increment the `likes` count locally
- Then call `api.likePost()`
- If `api.likePost()` throws an error, revert the count back to its original value
Ready to Learn React?
Start with the basics and work your way up to advanced patterns!
Start First Challenge