Custom hooks let you extract stateful UI behavior - keyboard offsets, sheet open state, debounced search, scroll-driven headers - into reusable functions that any screen or presentational component can call. You keep JSX in components and move the "how it works" into hooks, which cuts prop drilling without hiding business rules in visual trees.
Calling hooks conditionally - if (show) useFoo() violates the Rules of Hooks and crashes in dev. Fix: Call the hook unconditionally; gate behavior inside it or in the consumer.
Returning unstable objects every render - return { open, close, state: { isOpen } } where the inner object is recreated causes needless child re-renders. Fix: Memoize nested objects or flatten the return shape; stabilize callbacks with useCallback.
Mixing data fetching into UI hooks - useProductSheet that fetches and manages keyboard height is hard to test and reuse. Fix: Split into useProductQuery + useBottomSheet; compose at the screen.
Forgetting native listener cleanup - Keyboard and Dimensions listeners leak if remove() is skipped. Fix: Return a cleanup function from useEffect and call .remove() on subscriptions.
Sharing mutable refs across instances - Module-level let lastOffset = 0 bleeds state between screens. Fix: Keep mutable values in useRef inside the hook body.
Hooks that return JSX - A hook returning <Modal /> is a component, not a hook. Fix: Return state + handlers; let the caller render JSX (headless pattern - see Headless Components).
Over-abstracting one-off logic - A hook used exactly once adds indirection without reuse. Fix: Inline until the second consumer appears; then extract with a name that describes behavior, not the screen.