DEV Community

Eduardo Henrique Gris
Eduardo Henrique Gris

Posted on

Prop drilling in React

Introduction

Prop drilling corresponds to when props need to pass through several components before reaching the components that actually make use of them. In the illustration below, there is an example of this behavior:

Image description

In blue: component that obtains the data and passes it via props
In yellow: components that only pass the props along
In green: components that use the props

Problems

As information is passed through an increasing number of components before reaching those that use it, the following problems arise:

  • code maintenance: when a change occurs in the props being passed (for example its name), it may become necessary to modify all the components through that it passes
  • code comprehension: it complicates understanding the flow of information and locating where it is used due to the number of components it passes
  • less reusable components: it adds coupling between components, reducing their flexibility

React Context

One way to solve the problem of prop drilling is by using Context, which allows accessing data inside a component tree without manually passing props through each level until reaching the component that uses it. Below is an example of this behavior:

Image description

In blue: component that obtains the data and provides it
In green: components that use the data

Example of passing props

Image description

data flow:

  • ComponentA: has data and passes it via props
import React from "react"
import ComponentB from "./ComponentB"

const ComponentA = () => {
  const data = "Component A text"

  return(
    <>
      //...
      <ComponentB data={data} />
    </>
  )
};

export default ComponentA;
Enter fullscreen mode Exit fullscreen mode
  • ComponentB: a child of ComponentA that passes data via props
import React from "react"
import ComponentC from "./ComponentC"

const ComponentB = ({data}) => (
  <>
    //...
    <ComponentC data={data} />
  </>
);

export default ComponentB;
Enter fullscreen mode Exit fullscreen mode
  • ComponentC: a child of ComponentB that uses data
import React from "react"

const ComponentC = ({data}) => (
  <>
    //...
    {data}
  </>
);

export default ComponentC;
Enter fullscreen mode Exit fullscreen mode

Example using Context

Image description

data flow:

  • DataContext: creation of the context that will provide the data from ComponentA
import { createContext } from 'react'

export const DataContext = createContext()
Enter fullscreen mode Exit fullscreen mode

createContext: allows creating a context that components can provide data or access data from

  • ComponentA: has data and provides it through the Provider of DataContext
import React from "react"
import { DataContext } from "./DataContext"
import ComponentB from "./ComponentB"

const ComponentA = () => {
  const data = "Component A text"

  return(
    <DataContext.Provider value={data}>
      <ComponentB />
    </DataContext.Provider>
  )
};

export default ComponentA;
Enter fullscreen mode Exit fullscreen mode

Provider: provides the defined value to all components inside it, in this case data, regardless of the component's level

  • ComponentC: uses the useContext hook to access the data provided by ComponentA
import React, { useContext } from "react"
import { DataContext } from "./DataContext"

const ComponentC = () => {
  const text = useContext(DataContext)

  return(
    <>
      //...
      {text}
    </>
  )
};

export default ComponentC;
Enter fullscreen mode Exit fullscreen mode

useContext: for the component that calls the hook, it allows access to value, in this case data

Conclusion

The idea of this article is to define prop drilling and the problems that arise from it, which become more pronounced as props pass through more components that do not use them. As an alternative, the use of React Context is presented with the goal of mitigating these problems.

Top comments (0)