Beyond Hooks: Exploring Custom React Patterns for Scalable Applications

Beyond Hooks: Exploring Custom React Patterns for Scalable Applications

In today’s React ecosystem, hooks have become synonymous with writing modern and reusable components. But as applications scale, the need for more structured and tailored patterns becomes evident. In this article, I’ll explore some lesser-discussed but highly effective patterns for building scalable and maintainable React applications.


  • Compound Component Pattern

When building complex components like modals, tabs, or dropdowns, the compound component pattern shines. It allows you to provide a set of components that work together while maintaining flexibility for the consumer.

Example: Building a Custom Tabs Component

import { useState, Children, cloneElement } from "react";

const Tabs = ({ children }) => {
  const [activeTab, setActiveTab] = useState(0);

  return (
    <div>
      {Children.map(children, (child, index) => {
        return cloneElement(child, {
          activeTab,
          setActiveTab,
          index,
        });
      })}
    </div>
  );
};

Tabs.Tab = ({ index, activeTab, setActiveTab, children }) => (
  <button
    style={{ fontWeight: activeTab === index ? "bold" : "normal" }}
    onClick={() => setActiveTab(index)}
  >
    {children}
  </button>
);

Tabs.Panel = ({ index, activeTab, children }) => {
  return activeTab === index ? <div>{children}</div> : null;
};

// Usage
<Tabs>
  <Tabs.Tab>Tab 1</Tabs.Tab>
  <Tabs.Tab>Tab 2</Tabs.Tab>
  <Tabs.Panel>Content for Tab 1</Tabs.Panel>
  <Tabs.Panel>Content for Tab 2</Tabs.Panel>
</Tabs>        

This pattern ensures that your components remain cohesive yet customizable.


  • Render Props Pattern

Render props are a flexible way to share logic between components. Although hooks have replaced many use cases, render props still excel when you want complete control over the rendered output.

Example: Mouse Tracker

import { useState } from "react";

const MouseTracker = ({ children }) => {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleMouseMove = (e) => {
    setPosition({ x: e.clientX, y: e.clientY });
  };

  return (
    <div style={{ height: "100vh" }} onMouseMove={handleMouseMove}>
      {children(position)}
    </div>
  );
};

// Usage
<MouseTracker>
  {({ x, y }) => <h1>The mouse is at ({x}, {y})</h1>}
</MouseTracker>        

This pattern gives full control to the consuming component while encapsulating the reusable logic.


  • Controlled vs. Uncontrolled Components

Managing forms in React can get tricky, especially in large apps. Leveraging controlled and uncontrolled components appropriately can simplify state management.

Tip:

  • Use controlled components when you need real-time validation or state synchronization.
  • Use uncontrolled components for simple scenarios where refs can suffice.

Example:

import { useRef } from "react";

const UncontrolledForm = () => {
  const inputRef = useRef();

  const handleSubmit = (e) => {
    e.preventDefault();
    alert(`Input Value: ${inputRef.current.value}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input ref={inputRef} />
      <button type="submit">Submit</button>
    </form>
  );
};        

This distinction ensures better performance and clarity when handling user inputs.


  • Higher-Order Components (HOCs)

While hooks have largely replaced HOCs, they’re still valuable for cross-cutting concerns like logging or performance tracking.

Example: Logging Props

import { useEffect } from "react";

const withLogger = (WrappedComponent) => {
  return (props) => {
    useEffect(() => {
      console.log("Props: ", props);
    }, [props]);

    return <WrappedComponent {...props} />;
  };
};

const MyComponent = ({ name }) => <div>Hello, {name}</div>;

const LoggedComponent = withLogger(MyComponent);

// Usage
<LoggedComponent name="React" />;        

This demonstrates how HOCs can abstract repetitive logic effectively.


Final Thoughts

While hooks are indispensable in modern React, leveraging advanced patterns like compound components, render props, and HOCs ensures scalability and flexibility as your app grows. These patterns may not be new, but their thoughtful implementation can make a world of difference in your project’s architecture.

#ReactJS #WebDevelopment #JavaScript #Programming #SoftwareEngineering #FrontendDevelopment #ReactPatterns #ScalableApps #CleanCode #TechInsights


AYUSH TRIPATHI

60k+ FOLLOWERS || SR. SOFTWARE DEVELOPER || REACTJS || VUEJS || REACT NATIVE || NODEJS || NEXTJS || GRAPHQL || JEST || AWS || WhatsApp: 8700969004

1w

Insightful

Like
Reply
Nishu Srivastava

Frontend Developer @ Comhard Technologies Pvt Ltd

1w

Very informative

Like
Reply

To view or add a comment, sign in

Insights from the community

Others also viewed

Explore topics