Custom Hooks
Custom hooks are JavaScript functions starting with 'use' that compose built-in hooks to extract and reuse stateful logic across components. They share logic, not state — each component using the hook gets its own independent state.
A custom hook is a recipe — two chefs following the same recipe each make their own separate dish. The recipe (logic) is shared, but the dishes (state) are independent.
Custom hooks are the primary mechanism for code reuse in modern React, replacing mixins, HOCs, and render props for most use cases. Examples: useLocalStorage, useFetch, useDebounce, useMediaQuery. They can call any other hook and return whatever the consumer needs — state, callbacks, refs, JSX. The 'use' prefix is required so React's linter can enforce the rules of hooks inside them.
Custom hooks enable the 'headless component' pattern — hooks that manage all the logic (state machines, keyboard navigation, ARIA attributes) while the consumer provides the UI. Libraries like Downshift and React Aria use this pattern. A well-designed custom hook has a clear API surface (like a component's props), handles cleanup properly, and documents its re-render characteristics. Testing custom hooks is done via renderHook from React Testing Library, which creates a thin wrapper component.
Custom hooks extract reusable stateful logic into functions prefixed with 'use'. Each consumer gets independent state — hooks share logic, not state. I use them to build headless components, encapsulate fetch/subscription logic, and keep components focused on rendering. They fully replace HOCs and render props for most reuse patterns.
Assuming two components using the same custom hook share state. They don't — each call creates independent state. If you need shared state, use context or an external store inside the hook.