Props are great for passing data, but threading the same value through several layers of components that don't actually use it is the problem known as prop drilling. The Context API solves it by letting a value be declared once near the top of the tree and read by any descendant that needs it. A context is created with React.createContext(defaultValue), supplied to a subtree via a Provider component that sets value, and consumed by any descendant with useContext(MyContext). When the provided value changes, every consumer re-renders.
Sometimes the right answer is not context but lifting state up. If two siblings need to stay in sync, you move the shared state into their closest common ancestor and pass it down as props. The ancestor becomes the single source of truth. To let a child send data back up to its parent — for instance, reporting a form submission — the parent passes a callback as a prop, and the child invokes it with the new value. This keeps the unidirectional flow intact even when information needs to travel against the tree.
Composition patterns reinforce the same idea. Higher-Order Components (HOCs) are functions that take a component and return an enhanced version, a technique useful for cross-cutting concerns like authentication, logging, and theming. Custom hooks go one step further: they are JavaScript functions whose names start with use and may call other hooks. They let you extract and reuse stateful logic across components without changing the component hierarchy. Both patterns are tools for reusing behavior, and the modern preference is usually custom hooks.