Skip to content

Dummy project specifically aimed at understanding and implementing different design patterns in a React application

Notifications You must be signed in to change notification settings

swathign-sbdinc/DesignPatterns

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 

Repository files navigation

React Design Patterns Exploration

Welcome to the React Design Patterns Exploration repository. This project serves as a sandbox to explore and understand different design patterns commonly used in React applications. Each design pattern is explained, and examples are provided to illustrate their implementation.

Table of Contents


Container/Component Pattern

Description

The Container/Component pattern involves dividing components into two categories: container components and presentational components. Container components manage data logic and state, while presentational components focus solely on rendering UI.

Pros

  • Clean separation of concerns.
  • Improved code organization and maintainability.
  • Enhanced component reusability.
  • Facilitates easier testing.

Cons

  • Slight increase in boilerplate code due to separate container components.

Suitability

Ideal for larger applications where data management and UI rendering can be decoupled. Promotes reusability and maintainability.

Example

Check ContainerComponent.js and PresentationalComponent.js.

// ContainerComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchData } from '../actions';
import PresentationalComponent from './PresentationalComponent';

class ContainerComponent extends Component {
  componentDidMount() {
    this.props.fetchData();
  }

  render() {
    return <PresentationalComponent data={this.props.data} />;
  }
}

const mapStateToProps = state => ({
  data: state.data
});
export default connect(mapStateToProps, { fetchData })(ContainerComponent);

// PresentationalComponent.js
import React from 'react';

const PresentationalComponent = ({ data }) => (
  <div>
    {data.map(item => (
      <div key={item.id}>{item.name}</div>
    ))}
  </div>
);

export default PresentationalComponent;

Presentational/Component Pattern

Description

An extension of the container/component pattern, the Presentational/Component pattern further divides components into presentational and container components. Presentational components handle UI rendering, while container components handle data logic.

Pros

  • Clear separation of concerns.
  • High component reusability.
  • Improved code readability.

Cons

  • May result in a larger number of small components, which could be overwhelming in small projects.

Suitability

Ideal for projects with complex UIs that require a high level of reusability and modularity.

Example

Check PresentationalComponent.js and ContainerComponent.js.

import React from 'react';

const PresentationalComponent = ({ data }) => (
  <div>
    {data.map(item => (
      <div key={item.id}>{item.name}</div>
    ))}
  </div>
);
import React, { Component } from 'react';
import { fetchData } from '../actions';
import PresentationalComponent from './PresentationalComponent';

class ContainerComponent extends Component {
  componentDidMount() {
    this.props.fetchData();
  }

  render() {
    return <PresentationalComponent data={this.props.data} />;
  }
}

export default ContainerComponent;
export default PresentationalComponent;

Render Props

Description

The Render Props pattern is a technique used in React where a component receives a function as a prop. This function, known as the render function, provides content that the component will render. It's a way to share behavior between components without relying on inheritance or complex component hierarchies.

Pros

  • Highly flexible and dynamic approach to component composition.
  • Promotes code sharing and reusability, as multiple components can use the same render function.
  • Allows decoupling of behavior from components, leading to cleaner and more maintainable code.

Cons

  • May lead to nested components and layers of indentation if not managed properly.
  • Can introduce a learning curve for those unfamiliar with the pattern.

Suitability

Effective for scenarios where you want to share behavior between components that don't have a direct parent-child relationship. It's particularly useful when you need dynamic rendering and customization.

Example

Check RenderPropsComponent.js.


RenderPropsComponent.js

import React from 'react';

const RenderPropsComponent = ({ renderFunction }) => (
  <div>
    {renderFunction('Hello from Render Props')}
  </div>
);

export default RenderPropsComponent;

###Usage: You can use the RenderPropsComponent by passing a render function as a prop.

import React from 'react';
import RenderPropsComponent from './RenderPropsComponent';

const App = () => (
  <div>
    <RenderPropsComponent
      renderFunction={content => <h1>{content}</h1>}
    />
  </div>
);

export default App;

Higher-Order Components (HOCs)

Description

Higher-Order Components (HOCs) are a design pattern in React where functions are used to enhance components by adding extra functionality. HOCs take a base component and return an extended version of that component, allowing the addition of shared behaviors without altering the original component's implementation.

Pros

  • Enables efficient code reuse and separation of concerns by encapsulating common functionality in HOCs.
  • Modifies component behavior without requiring changes to the underlying component itself.
  • Offers an organized approach to managing cross-cutting concerns.

Cons

  • May lead to "wrapper hell," where multiple layers of nested HOCs can complicate the component hierarchy.
  • Can increase the complexity of understanding component behavior due to the indirect nature of modifications.

Suitability

Ideal for scenarios where you want to add consistent and reusable functionalities to multiple components across your application.

Example

Check withLogger.js.

// withLogger.js
import React from 'react';

const withLogger = WrappedComponent => {
  return class extends React.Component {
    componentDidMount() {
      console.log('Component did mount');
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
};

export default withLogger;
---
Usage:
Apply the HOC to a component to add logging behavior.

```jsx
jsx
Copy code
import React from 'react';
import withLogger from './withLogger';

const ComponentWithLogger = withLogger(MyComponent);

export default ComponentWithLogger;

Hooks

Description

Hooks are special functions in React that allow you to use state and other React features without writing class components. They provide a more concise and functional approach to managing state, lifecycle, and side effects in functional components.

Pros

  • Simplifies component logic by encapsulating stateful and side-effectful code within functions.
  • Avoids the complexity of class components and eliminates the need for constructor and lifecycle methods.
  • Enhances code readability and maintainability by promoting a more straightforward component structure.

Cons

  • Requires a mindset shift for developers accustomed to class components and traditional React practices.
  • Some custom hooks might not be as performant as their class component equivalents, depending on how they're implemented.

Suitability

Perfect for modern React applications that aim to efficiently manage state, lifecycle, and side effects. Hooks are particularly useful in functional components, making them a core feature of contemporary React development.

Example

Check useCounter.js. Custom Hook: Here's an example of a custom hook for managing a simple counter.

// useCounter.js
import { useState } from 'react';

const useCounter = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return { count, increment };
};

export default useCounter;

Usage: Use the useCounter custom hook in a functional component.

Copy code
import React from 'react';
import useCounter from './useCounter';

const CounterComponent = () => {
  const { count, increment } = useCounter();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

export default CounterComponent;

Project Setup

  1. Clone this repository.
  2. Navigate to each example folder and explore the patterns.
  3. Run npm install and npm start within each example folder to see the patterns in action.

About

Dummy project specifically aimed at understanding and implementing different design patterns in a React application

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published