Extract Duplicated Stateful Logic into Custom Hooks
Impact: MEDIUM (reduces code duplication and ensures consistent behavior across components)
When the same combination of useState, useEffect, useRef, or useCallback appears in multiple components — such as fetching data, managing form state, handling window resize, debouncing input, or tracking online status — each copy is an independent maintenance burden. Bug fixes must be applied in every location, and subtle inconsistencies creep in. Custom hooks encapsulate this logic once, making it testable in isolation and reusable everywhere.
Common candidates for custom hooks: useDebounce, useLocalStorage, useMediaQuery, useOnClickOutside, useIntersectionObserver, usePrevious, useWindowSize.
Custom hooks are testable in isolation using renderHook from @testing-library/react.
If your custom hook becomes too complex (> 50 lines, multiple branching paths), it may need to be split further or replaced with a dedicated library (TanStack Query for data fetching, React Hook Form for forms).
Naming convention: custom hooks must start with use to get lint rule enforcement from the Rules of Hooks.