Module 10: Advanced React Patterns

Master advanced React patterns including Higher-Order Components, Render Props, Compound Components, and advanced patterns for building reusable and maintainable components.

Back to Course|5 hours|Advanced

Advanced React Patterns

Master advanced React patterns including Higher-Order Components, Render Props, Compound Components, and advanced patterns for building reusable and maintainable components.

Progress: 0/4 topics completed0%

Select Topics Overview

Higher-Order Components

Master Higher-Order Components (HOCs) to create reusable logic and enhance components with cross-cutting concerns.

Content by: Praveen Kumar

MERN Stack Developer

Connect

Understanding HOCs

Higher-Order Components are functions that take a component and return a new component with additional functionality. They are a powerful pattern for code reuse and logic sharing in React applications.

Basic HOC Implementation

Code Example
// Basic HOC example
function withLoading(WrappedComponent) {
    return function WithLoadingComponent({ isLoading, ...props }) {
        if (isLoading) {
            return <div>Loading...</div>;
        }
        return <WrappedComponent {...props} />;
    };
}

// Usage
const UserProfile = ({ user }) => <div>{user.name}</div>;
const UserProfileWithLoading = withLoading(UserProfile);
Swipe to see more code

Advanced HOC Patterns

Code Example
// HOC with state and lifecycle
function withData(WrappedComponent) {
    return class extends React.Component {
        constructor(props) {
            super(props);
            this.state = { data: null, loading: true };
        }
        
        componentDidMount() {
            this.fetchData();
        }
        
        fetchData = async () => {
            try {
                const data = await api.getData();
                this.setState({ data, loading: false });
            } catch (error) {
                this.setState({ error, loading: false });
            }
        }
        
        render() {
            return <WrappedComponent {...this.props} {...this.state} />;
        }
    };
}
Swipe to see more code

HOC Best Practices

  • Don't mutate the original component
  • Pass through unrelated props
  • Maximize composability
  • Display name for debugging
  • Don't use HOCs inside render method
  • Copy static methods if needed

Common HOC Examples

Code Example
// Authentication HOC
const withAuth = (WrappedComponent) => {
    return function AuthenticatedComponent(props) {
        const { user, isAuthenticated } = useAuth();
        
        if (!isAuthenticated) {
            return <LoginPage />;
        }
        
        return <WrappedComponent {...props} user={user} />;
    };
};

// Error Boundary HOC
const withErrorBoundary = (WrappedComponent) => {
    return class extends React.Component {
        constructor(props) {
            super(props);
            this.state = { hasError: false };
        }
        
        static getDerivedStateFromError(error) {
            return { hasError: true };
        }
        
        componentDidCatch(error, errorInfo) {
            console.error('Error caught by HOC:', error, errorInfo);
        }
        
        render() {
            if (this.state.hasError) {
                return <div>Something went wrong.</div>;
            }
            
            return <WrappedComponent {...this.props} />;
        }
    };
};
Swipe to see more code

Mini-Project: Data Fetching HOC

Code Example
// Complete data fetching HOC with caching
import React, { useState, useEffect, useCallback } from 'react';

const withDataFetching = (url, options = {}) => (WrappedComponent) => {
    return function WithDataFetching(props) {
        const [data, setData] = useState(null);
        const [loading, setLoading] = useState(true);
        const [error, setError] = useState(null);
        const [refetch, setRefetch] = useState(0);
        
        const fetchData = useCallback(async () => {
            try {
                setLoading(true);
                setError(null);
                const response = await fetch(url, options);
                const result = await response.json();
                setData(result);
            } catch (err) {
                setError(err.message);
            } finally {
                setLoading(false);
            }
        }, [url, JSON.stringify(options)]);
        
        useEffect(() => {
            fetchData();
        }, [fetchData, refetch]);
        
        const handleRefetch = () => setRefetch(prev => prev + 1);
        
        return (
            <WrappedComponent
                {...props}
                data={data}
                loading={loading}
                error={error}
                refetch={handleRefetch}
            />
        );
    };
};

// Usage example
const UserList = ({ data, loading, error, refetch }) => {
    if (loading) return <div>Loading users...</div>;
    if (error) return <div>Error: {error}</div>;
    
    return (
        <div>
            <button onClick={refetch}>Refresh</button>
            <ul>
                {data?.map(user => (
                    <li key={user.id}>{user.name}</li>
                ))}
            </ul>
        </div>
    );
};

const UserListWithData = withDataFetching('/api/users')(UserList);

export default UserListWithData;
Swipe to see more code

🎯 Practice Exercise

Test your understanding of this topic:

Additional Resources

📚 Recommended Reading

  • React Advanced Patterns Guide
  • Higher-Order Components Documentation
  • Render Props Pattern Guide
  • Compound Components Best Practices

🌐 Online Resources

  • Advanced React Patterns Tutorial
  • React Component Composition
  • Reusable Component Design
  • React Performance Patterns

Ready for the Next Module?

Continue your learning journey and master the next set of concepts.

Continue to Module 11