Module 5: Advanced Patterns

Custom Hooks, Reducers, and Performance.

1. Core Concepts

Custom Hooks: JavaScript functions that start with use... and call other hooks. They allow you to share logic (like fetching or form handling) between components without sharing UI.

useReducer: An alternative to useState for complex logic. You dispatch "actions" (instructions) to a "reducer" (function) that calculates the new state.

Memoization (useMemo/useCallback): Performance tools. They tell React: "If these inputs haven't changed, don't re-calculate this value or re-create this function."

1.1 Deep Dive: The Rules of Hooks

Hooks are magic, but they have rules. They rely on call order.
1. Only call hooks at the top level. Never inside loops, conditions, or nested functions.
2. Only call hooks from React functions.

1.2 Industry Standard: The "use" Prefix

If a function uses a hook, it must be named useSomething. This is not just a convention; linters rely on it to enforce the Rules of Hooks. If you write a helper function that calls useContext but name it getAuth(), you will break the linter and potentially your app.

📚 Deep Dive (Documentation)
REQ-006 To Do

Refactor to Custom Hooks

User Story

As a developer, I want to reuse logic across components so that I don't violate DRY (Don't Repeat Yourself) principles.

Acceptance Criteria
  • useFetch(url):
    • Accepts a URL string.
    • Returns { data, loading, error }.
    • Handles AbortController to cancel requests on unmount.
  • useLocalStorage(key, initialValue):
    • Syncs state with localStorage.
    • Updates storage when state changes.
    • Initializes from storage if available.
Senior Bonus
  • Generics: Make useFetch<T> and useLocalStorage<T> type-safe.
  • useWindowSize: Create a hook that tracks window dimensions. MUST remove the event listener on unmount.
  • useDebounce: Create a hook to delay API calls in the search bar (500ms delay).
REQ-007 Complex State with useReducer

User Story: As a developer, I need to manage a complex shopping cart state where multiple actions (add, remove, update quantity, clear) affect the same data.

Acceptance Criteria:

  • Create a `cartReducer` function.
  • Handle actions: `ADD_ITEM`, `REMOVE_ITEM`, `UPDATE_QTY`, `CLEAR_CART`.
  • Use `useReducer` in the `CartContext`.
  • Ensure state updates are immutable.

3. The Bug Hunt

🐛 Scenario: The Expensive Calculation

The Setup:

function Dashboard({ data }) {
  // This runs on EVERY render, even if 'data' hasn't changed!
  const processedData = expensiveMathOperation(data); 
  return <Chart data={processedData} />;
}

The Bug: The dashboard is laggy because expensiveMathOperation takes 200ms to run, and the component re-renders whenever the parent updates.

The Task:

  1. Wrap the calculation in useMemo.
  2. Explain why useMemo needs a dependency array.