Top React Design Patterns Every Frontend Developer Should Know bilal shafqat

Top React Design Patterns Every Frontend Developer Should Know

React is one of the most popular JavaScript libraries for building modern, interactive user interfaces. However, as applications grow in complexity, maintaining a clean and scalable architecture becomes crucial. To address this, developers rely on well-established design patterns to enhance code reusability, maintainability, and scalability.

In this article, we’ll explore the top React design patterns every frontend developer should know, complete with examples, pros, and cons.

1. Container-Presenter Pattern

Container-Presenter Pattern react design patterns bilal shafqat

The Container-Presenter pattern (also known as the Smart-Dumb pattern) separates logic from UI components, making applications easier to maintain and test.

Example:

// Container Component (Handles logic)
import React, { useState, useEffect } from 'react';
import UserList from './UserList';

const UserContainer = () => {
    const [users, setUsers] = useState([]);

    useEffect(() => {
        fetch("https://jsonplaceholder.typicode.com/users")
            .then(response => response.json())
            .then(data => setUsers(data));
    }, []);

    return <UserList users={users} />;
};

export default UserContainer;
// Presenter Component (Handles UI)
const UserList = ({ users }) => {
    return (
        <ul>
            {users.map(user => (
                <li key={user.id}>{user.name}</li>
            ))}
        </ul>
    );
};

export default UserList;

Pros:

  • Enhances code separation and reusability.
  • Improves testing as logic and UI are separate.
  • Makes components more readable and maintainable.

Cons:

  • Increases the number of components.
  • Can introduce boilerplate code.

2. Higher-Order Components (HOC)

higher order components hoc react design patterns bilal shafqat

HOCs are functions that wrap a component to add extra functionality without modifying the original component.

Example:

const withLoading = (WrappedComponent) => {
    return ({ isLoading, ...props }) => {
        if (isLoading) return <p>Loading...</p>;
        return <WrappedComponent {...props} />;
    };
};

const UserList = ({ users }) => (
    <ul>
        {users.map(user => (
            <li key={user.id}>{user.name}</li>
        ))}
    </ul>
);

export default withLoading(UserList);

Pros:

  • Promotes code reuse across multiple components.
  • Keeps components pure and clean.

Cons:

  • Debugging can be complex due to multiple layers of abstraction.
  • Naming conflicts with props are possible.

3. Render Props

Render Props react design patterns bilal shafqat

Render props allow components to share code logic using a function passed as a prop.

Example:

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

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

    return <div onMouseMove={handleMouseMove}>{render(position)}</div>;
};

const App = () => (
    <MouseTracker render={({ x, y }) => (
        <p>Mouse position: {x}, {y}</p>
    )} />
);

Pros:

  • Allows dynamic logic sharing.
  • Provides more control than HOCs.

Cons:

  • Can cause deep nesting (callback hell).
  • Less readable compared to other patterns.

4. Compound Components

Compound Components top 5 react design patterns bilal shafqat

The Compound Component pattern allows components to communicate without relying on props.

Example:

const Tabs = ({ children }) => {
    const [activeIndex, setActiveIndex] = useState(0);
    return React.Children.map(children, (child, index) =>
        React.cloneElement(child, { activeIndex, setActiveIndex, index })
    );
};

const Tab = ({ children, activeIndex, setActiveIndex, index }) => (
    <button onClick={() => setActiveIndex(index)}
            style={{ fontWeight: activeIndex === index ? 'bold' : 'normal' }}>
        {children}
    </button>
);

const Content = ({ children, activeIndex, index }) => {
    return activeIndex === index ? <div>{children}</div> : null;
};

const App = () => (
    <Tabs>
        <Tab>Tab 1</Tab>
        <Content>Content for Tab 1</Content>
        <Tab>Tab 2</Tab>
        <Content>Content for Tab 2</Content>
    </Tabs>
);

Pros:

  • Provides a clean API for building reusable UI components.
  • Avoids prop drilling.

Cons:

  • Can be harder to implement correctly.
  • Requires more understanding of React internals.

5. Custom Hooks

Custom Hooks top 5 react design patterns bilal shafqat

Custom hooks encapsulate reusable logic and allow better separation of concerns.

Example:

const useFetch = (url) => {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        fetch(url)
            .then(response => response.json())
            .then(data => {
                setData(data);
                setLoading(false);
            });
    }, [url]);

    return { data, loading };
};

const Users = () => {
    const { data: users, loading } = useFetch('https://jsonplaceholder.typicode.com/users');
    return loading ? <p>Loading...</p> : <ul>{users.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
};

Pros:

  • Promotes code reuse and modularity.
  • Keeps components clean and focused.

Cons:

  • Requires understanding of React hooks.
  • Overuse can lead to too many custom hooks.

Frequently Asked Questions (FAQ)

1. What is the best design pattern for a React project?

The best pattern depends on the project’s complexity. For scalable apps, Container-Presenter and Custom Hooks are great choices.

2. Are HOCs still relevant in React?

While HOCs are still used, Render Props and Custom Hooks are often preferred due to better readability and maintainability.

3. When should I use Compound Components?

Use Compound Components when building UI components that need internal state management without excessive props drilling, such as Tabs or Dropdowns.

4. How do I choose between Custom Hooks and Render Props?

Use Custom Hooks when handling stateful logic and Render Props for dynamic UI rendering.

Conclusion

React design patterns help in writing clean, maintainable, and scalable applications. By mastering these patterns, you can improve your codebase and development workflow.

Which pattern is your favorite? Let us know in the comments!

 

Leave A Comment