What is prop drilling?

Prop drilling is when a prop is passed to a Component only for the sole purpose of passing it down to a child.”

In React, it is pretty common to find yourself writing a lot of boilerplate code for passing a value to a component, only to pass that component down again to a child, and this can be repeated as many times with many children as needed, until the data you are passing down reaches the component where you need it.

Not only this will cause a considerable amount of extra code written, but it will also affect the architectural design of your component, which will now require to have a property that the component itself will not even use, the prop is there just to be passed down the chain until it reaches the final component that will, in fact, use it for something. This issue is even more noticeable in apps written using a global state approach, where all the app state is saved in a global object.

In the previous image, the arrows represent the way the data needs to flow down to reach the components where it is needed; the lower in the three the component that needs the data is, the more drilling needs to be done to reach it.

React Context has always existed within React, it was previously shipped with an experimental context API and it was created with the sole purpose of getting rid of prop drilling, react itself has used it internally for a long time, but it was only until March 2018 that a completely revamp version of the context API that we can now use was released. This new version will not only help us to avoid prop drilling, but it’s now possible to use that context approach to manage our application state. Hey! We can even replace redux and only use vanilla react without any extra library to manage our centralized state architecture.

In the following image, we can see how with React Context, we just make the values available from everywhere in the chain instead of passing them down in the form of properties to other components, we do so by wrapping the components in a context that can be accessed from any position in the tree.

You can now see how there is only one arrow and that we no longer need to be passing down values over and over again to reach our farthest components.

Now with some code examples

Using Prop Drilling to pass down data example:

1) We mount our main element Toggle.

2) Inside Toggle, we can see how the Switch component saves the state and passes it down by using props, on property for printing the button state and OnToggle function for changing the actual state.

You can visit a working demo here: https://codesandbox.io/s/prop-drilling-mpzen

 

Now an Example using React Context:

1) First, we need to create a React Context (React.createContext) with some default values for our state, “on” will be started as false and let’s make onToggle an empty function for now. This created react context, which will give us access to a context provider and a context consumer:

  • ToggleContext.Provider: This will make the context available for every child.
  • ToggleContext.Consumer: When inside a Provider, it will allow us to read the context.

2) Lets make <ToggleContext.Provider> component a bit more intelligent by adding our state and our custom function (toggle) to toggle the switch value between on and off.

In order to do this, we need to initialize our Provider with the “on” and toggle values via its value property and then make sure we pass down all the children inside.

3) This will give us our custom ToggleContexProvider that we can now use to wrap the entire application in, and since Toggle lives inside a Context Provider we can use a Context.Consumer from any child to read the state provided by ToggleContexProvider

4) This is the rest of the code, notice how we use ToggleContext.Consumer for accessing whatever objects we used in values={} for our Custom Provider, also notice how we can use it directly inside the component where we need it, instead of passing it down every time, avoiding prop drilling.

Usage:

Implementation:

In the example above, we used a React Context to wrap the entire state of our small application, but you can use several different contexts for each of your app’s concerns and abstract your logic in different files.

You can visit a working demo here: https://codesandbox.io/s/53pq01x144

 

Conclusion:

Sometimes having a centralized-managed state is very similar to having a globally declared variable, this is often avoided because it leads to having a very confusing data model for your application, answering the question “can I modify this without breaking the app?”, which is sometimes very difficult to answer.

Prop drilling helps with this without any doubt, but we need to keep its downsides in mind. Use prop drilling only when you want to be very specific about how the data flows and you want to make clear dependencies between components, but use react context for normally managing the state in the rest of your application.

If you want to learn more on how to use context, here is a great place to start: https://reactjs.org/docs/context.html

 

References:

https://www.youtube.com/watch?v=u0slAvqjA6E

Code examples inspired by:
https://kentcdodds.com/blog/prop-drilling