Lessons in this course (17)

9. useContext and useReducer

Intermediate★ Must knowLesson 9 of 17
jsx
const AuthContext = createContext(null);

function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const value = useMemo(() => ({ user, login: setUser, logout: () => setUser(null) }), [user]);
  return <AuthContext value={value}>{children}</AuthContext>;      // React 19: <Context> as provider (older: <AuthContext.Provider>)
}
const useAuth = () => {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
  return ctx;
};

// useReducer: complex state transitions in one place
function cartReducer(state, action) {
  switch (action.type) {
    case "add": return { ...state, items: [...state.items, action.item] };
    case "remove": return { ...state, items: state.items.filter(i => i.id !== action.id) };
    case "clear": return { ...state, items: [] };
    default: throw new Error(`Unknown action ${action.type}`);
  }
}
const [cart, dispatch] = useReducer(cartReducer, { items: [] });
dispatch({ type: "add", item: { id: 7, name: "Mouse", price: 900 } });

Context avoids prop drilling for app-wide values (theme, auth, locale). Every consumer re-renders when the context value changes — split contexts, memoise the value, or use a state library for frequently changing global state.