Published on

Why Should We Use React Composition to Avoid Props Drilling?

Authors

Intro

Using React Composition to avoid prop drilling can help to make your component hierarchy cleaner and more maintainable. By using a higher-order component to share state between components, you can avoid the need to pass props through multiple levels of components, which can make your component tree easier to understand and maintain.

Target Audience

I've aimed this article at people who want to learn about react composition.

Learning Objectives

After completing this article, you will know how to do the following:

  • Understand what react composition is
  • Deconstructure your components using react composition
  • What is props drilling?
  • An Example case to use React Composition to avoid props drilling

What is React Composition ?

React Composition is a pattern that allows you to share stateful logic between components by creating a higher-order component that wraps a child component and provides the necessary state and behavior. This can be a useful approach when you have complex state logic that you want to reuse across multiple components.

What is props drilling ?

Props drilling refers to the practice of passing props down through multiple levels of components in a React application. This often occurs when a top-level component has some state that needs to be accessed by a deeply nested component. In order to pass the state down to the nested component, the props must be passed through every intermediate component in the hierarchy, which can make the component tree difficult to understand and maintain.

For example, imagine that you have a top-level App component that holds some state, and a deeply nested Footer component that needs to access that state. In order to pass the state from the App component to the Footer component, you would need to pass the state through every intermediate component in the hierarchy, like this:

class App extends React.Component {
  state = {
    user: {
      name: 'John Doe',
      email: 'johndoe@example.com',
    },
  }

  render() {
    return (
      <div>
        <Header user={this.state.user} />
        <Content user={this.state.user} />
      </div>
    )
  }
}

function Header(props) {
  return <h1>Welcome, {props.user.name}!</h1>
}

function Content(props) {
  return (
    <p>
      Your email is: {props.user.email}
      <Footer user={props.user} />
    </p>
  )
}

function Footer(props) {
  return <p>Copyright {props.user.name}</p>
}

An example use case to avoid props drilling

// This is the top-level component that has the state you want to share
class App extends React.Component {
  state = {
    user: {
      name: 'John Doe',
      email: 'johndoe@example.com',
    },
  }

  render() {
    return (
      <div>
        <Header user={this.state.user} />
        <Content user={this.state.user} />
      </div>
    )
  }
}

// This is the higher-order component that provides the state to the child component
function withUser(WrappedComponent) {
  return class extends React.Component {
    render() {
      return <WrappedComponent user={this.props.user} {...this.props} />
    }
  }
}

// These are the two child components that will receive the state from the higher-order component
function Header(props) {
  return <h1>Welcome, {props.user.name}!</h1>
}

function Content(props) {
  return <p>Your email is: {props.user.email}</p>
}

// This is how you would use the higher-order component to wrap the child components
// and provide them with the shared state
const EnhancedHeader = withUser(Header)
const EnhancedContent = withUser(Content)

In this example, the withUser higher-order component provides the user state to the Header and Content child components. This allows the child components to access the user state without needing to pass it down through multiple levels of components, which is known as "prop drilling." Using a higher-order component to share state like this can help to make your component hierarchy cleaner and more maintainable.