DEV Community

Cover image for Patterns Whose Day‑to‑Day Relevance in React Dropped After Hooks
Md Enayetur Rahman
Md Enayetur Rahman

Posted on

Patterns Whose Day‑to‑Day Relevance in React Dropped After Hooks

React 16.8 introduced Hooks, a new API that lets functional components manage state, side‑effects, context and more without classes. Hooks solved many of the problems that earlier reuse patterns addressed, so some of those patterns are now far less common. This article revisits four such patterns, explains why they once mattered, why Hooks replaced or simplified them, and where each pattern still earns its keep.


Higher‑Order Component (HOC)

How it works

A Higher‑Order Component is a function that receives a component and returns a new component with extra props, state or behaviour.

function withTimer(Wrapped) {{
  return function TimerHOC(props) {{
    const [time, setTime] = useState(Date.now());
    useEffect(() => {{
      const id = setInterval(() => setTime(Date.now()), 1000);
      return () => clearInterval(id);
    }}, []);
    return <Wrapped {...props} time={time} />;
  }};
}}
Enter fullscreen mode Exit fullscreen mode

Why it was useful pre‑Hooks

  • Allowed logic sharing for class components (before functional components could have state).
  • Libraries like recompose, react-redux and routing solutions exposed their APIs as HOCs.

Why it’s less useful now

  • Custom Hooks share the same logic with a simple useTimer() call, without adding an extra wrapper element or risking “wrapper‑hell”.
  • Hooks avoid prop‑name collisions and static‑property hoisting issues. citeturn0search0turn0search6

Where it still shines

  • When you must transform the render output (e.g. error boundaries, code‑splitting with React.lazy, spoofing forwardRef).
  • Cross‑cutting wrappers that need to intercept lifecycle methods can still be simpler as an HOC.

Render Props Pattern

How it works

A component receives a function as a prop (render or children) and calls it to render UI. The caller controls the rendered output.

<MousePosition>
  {{pos => <p>{{pos.x}}, {{pos.y}}</p>}}
</MousePosition>
Enter fullscreen mode Exit fullscreen mode

Why it was useful pre‑Hooks

  • Encapsulated reusable logic (mouse, dimensions, subscriptions) without inheritance.
  • Avoided multiple HOCs when only data, not visual structure, needed to be shared.

Why it’s less useful now

  • Hooks let you call useMousePosition() inside any component and get the data directly, eliminating nested functions and prop drilling.

Where it still shines

  • Libraries that must stay framework‑agnostic (works in Preact/solid).
  • Cases needing to pass a render‑time callback instead of data (e.g. virtualised list row renderers).

Container / Presentational Pattern

How it works

Split each feature into a “smart” Container component (data‑fetching, state) and a “dumb” Presentational component (markup only).

// Container
export function TodosContainer() {{
  const todos = useTodosQuery();
  return <TodosList todos={todos} />;
}}
Enter fullscreen mode Exit fullscreen mode

Why it was useful pre‑Hooks

  • Functional components could not hold state; Containers wrapped class components or HOCs to provide data.
  • Helped teams separate styling work from business logic.

Why it’s less useful now

  • Hooks let a single functional component fetch data (useQuery), hold local state and render markup. Extra Container wrappers are optional, not required.

Where it still shines

  • Large code‑bases that enforce separation‑of‑concerns or dedicated design systems.
  • When you want to expose list‑level hooks but keep item components pure.

Mixin Pattern

How it works

Old React.createClass({{ mixins: [...] }}) let an object inject methods and state into a component prototype.

Why it was useful pre‑Hooks

  • Provided code reuse in the earliest days of React (pre‑ES6 classes).
  • Simplified lifecycle subscription sharing across multiple components.

Why it’s less useful now

  • Mixins cause name clashes and hidden dependencies; the React team called them “harmful”.
  • Hooks give explicit, composable alternatives (useSubscription, useSomething) without modifying prototypes.

Where it still shines

  • Never for new code; use composition / hooks instead. For legacy createClass components, mixins remain a migration stop‑gap.

Conclusion

Hooks did not kill every advanced pattern, but they did remove the need for patterns that solely existed to smuggle state and side‑effects into otherwise stateless function components. HOCs, Render‑Props, Container/Presentational splits and Mixins now appear mostly in legacy code or niche edge‑cases. Today, reach for a custom Hook first; fall back to those patterns only when you need capabilities hooks can’t (yet) cover—such as transforming the tree, intercepting refs or wrapping entire sub‑trees.


Originally published 2025-08-04.

Top comments (0)