▶What is the difference between useState and useReducer?
useState is simpler for single state values or independent state updates. useReducer is better for complex state logic with multiple related updates or transitions between states. Use useReducer when you have: multiple state variables, interdependent updates, or logic that's easier to test in isolation. Example: form with 5 fields and validation rules = useReducer. Counter = useState. Both update synchronously unless wrapped in startTransition.
▶How do I optimize render performance in React?
Use React.memo to skip re-renders if props haven't changed, useMemo to cache expensive computations, and useCallback to stabilize function references. Never create new objects/arrays as default props or dependencies—move them outside components or inside useMemo. Profile with React DevTools Profiler to identify unnecessary renders. Server Components reduce client-side bundle size. For lists, use unique stable keys (never index).
▶What is the difference between useEffect and useLayoutEffect?
useEffect runs after the browser paints (async, safe for most use cases). useLayoutEffect runs before the browser paints (synchronous, use for DOM measurements/animations to prevent visual flicker). 99% of cases use useEffect. Use useLayoutEffect only when you read/write layout synchronously (e.g., position tooltips). Both cleanup if dependencies change or component unmounts.
▶How do I manage global state: Context API, Redux, or Zustand?
Context API: simple, built-in, but causes re-renders of all consumers when any value changes. Use for theme/auth/language. Redux: powerful, verbose, good for complex state + time-travel debugging. Zustand: minimal, performant, recommended for most new projects. Pattern: Redux for enterprise, Zustand for startups, Context for theme/auth only. React Query is for server state (data fetching), not client state.
▶What are custom hooks and when do I write one?
Custom hooks are functions that call other hooks and extract stateful logic into reusable units. Examples: useLocalStorage (persist state), useFetch (data fetching), useWindowSize (responsive). Write a custom hook when: logic is used in 2+ components, or it encapsulates a complex pattern. Always name it `use*` and only call hooks at the top level. Test custom hooks with React Testing Library's renderHook utility.
▶What is the impact of Concurrent Features and Suspense?
Concurrent Features (React 18+) allow React to pause and resume rendering, improving responsiveness. Suspense lets you handle async operations (data fetching, code splitting) cleanly. startTransition marks non-urgent updates so urgent ones (input) take priority. useTransition gives feedback on pending state. Combined: fast input response + clean loading states. Requires frameworks like Next.js App Router for data layer integration.
▶How do compound components and render props work?
Compound components: parent component exposes child components that work together (e.g., <Tabs><Tab><TabPanel>). Props passed to parent shared via Context, children are flexible. Render props: parent accepts a function as prop that returns JSX—gives parent control over rendering. Modern alternative: custom hooks. Compound components = cleaner API, render props = more control. Use compound components for public-facing UI libraries.