React developers often encounter scenarios where they must pass data/state from a top-level component to a deeply nested component. Prop drilling refers to transporting this data/state as props to the intended destination through intermediate components.
Consider a visual representation of the component tree for a simple furniture e-commerce site to understand the problem better:
Suppose the top-level App
Component has access to the state of our shopping cart; we want to update the state by changing the button color from green to grey whenever the user clicks the "Add to Cart"
button.
Let's implement the scenario above to understand it. Run the code and try clicking the "Add to Cart"
button.
import React from 'react'; require('./styles.css'); import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render( <App />, document.getElementById('root') );
changeColor
that is responsible for changing state.buttonColor
and changeColor
as props to ProductCard
component.ProductCard
component then passes the props it received to the Button
component.Button
component passes changeColor
props to the onClick
event. The event fires when the button is clicked and sets the state of button to color grey.backgroundColor
attribute from green to grey to signal that product has been added to cart.As can be observed from the code in the example app above, this approach is redundant and cumbersome even in a simple app. We pass state/data manually through components that don't require it, making our code cluttered and difficult to maintain. In addition, we may accidentally rename props midway through this 'drilling' process and run into bugs. These issues are compounded for large-scale applications, thus making this process infeasible.
There are three alternative solutions to solve the problem we encountered above:
For our example above, using Redux would needlessly involve an external library, and the Context API would pose issues with reusability and performance when the application is scaled up. Hence, component composition is a viable solution. The other two solutions may cater to different use cases involving prop drilling.
The app below shows modified code that uses composition with container components:
import React from 'react'; require('./styles.css'); import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render( <App />, document.getElementById('root') );
App
, which enables us to pass required props directly to Button
component.Details
and Button
components within ProductCard
. There are different ways to solve the issue of prop drilling. This article focused on component composition as a solution due to its effectiveness and simplicity for most use cases.