Prop Drilling is the process by which you pass data from one part of the React Component tree to another by going through other parts that do not need the data but only help in passing it around.Imagine someone living in Lagos, Nigeria placing an order on Amazon for a package. The package will have to go through many hands - it has to be flown by air to Nigeria, transported to the Lagos, moved from place to place until it gets into the hands of the buyer. At each stage, Amazon employs the services of people that do not 'care' about the product, they only help to 'pass' it to the person who cared - the buyer.
Prop drilling is similar: You pass data (props) from some FirstComponent
to
another SecondComponent
- which doesn't need the data to render but only passes it to
another ThirdComponent
, which also doesn't need it and may pass it to another FourthComponent
.
This may continue until the data gets to the ComponentNeedingProps
.
Consider the code snippet below:
import React from "react";
import "./styles.css";
export default function App() {
return (
<div className="App">
<FirstComponent content="Who needs me?" />
</div>
);
}
function FirstComponent({ content }) {
return (
<div>
<h3>I am the first component</h3>;
<SecondComponent content={content} />|
</div>
);
}
function SecondComponent({ content }) {
return (
<div>
<h3>I am the second component</h3>;
<ThirdComponent content={content} />
</div>
);
}
function ThirdComponent({ content }) {
return (
<div>
<h3>I am the third component</h3>;
<ComponentNeedingProps content={content} />
</div>
);
}
function ComponentNeedingProps({ content }) {
return <h3>{content}</h3>;
}
The content
prop is passed to FirstComponent
in the root component, App
.
But FirstComponent
does not need the prop to render, it only passes it to SecondComponent
, which
passes it to ThirdComponent
, which passes it to ComponentNeedingProps
. It is this component that
uses the content
prop to render content in <h3>{content}</h3>
.
Why is Prop Drilling a Problem?
Prop drilling doesn't have to be a problem. If we are passing data only between 2 or 3 levels, we are fine. It will be easy to trace the flow of data. But imagine, we are drilling 5 levels, or 10 levels, or 15.
How to Solve the Problem
Prop drilling is not a new problem in React (quite obviously), and there have been many solutions that let us pass data down to deeply nested Components.
One of which is Redux: You create a data store
and connect
any component to the store
and
voila, no matter where the component is positioned in the Component Tree it has access to the store.
React also has the concept of Context
which lets you create something like a
global data store
and any Component in 'context' can have access to the data store.
If you however want to solve this problem without using context, you can use Component Composition as suggested by the React Docs: If you only want to avoid passing some props through many levels, component composition is often a simpler solution than context.
You can learn more here Before You Use Context and also, check out Michael Jackson's thread on why you should avoid using the Context API.
How to Avoid Prop Drilling Using Component Composition
Component Composition is when you compose different Components, usually simple, together to create more complex functionality. If you have ever written a React app, I bet that you have been composing components. Take for example:
function LoginForm(props){\
return (\
<Input name="fname" />\
<Button onClick={props.handleClick} />)
}
Here, by using composition we are creating a 'complex' functionality, LoginForm
by composing two
simpler functionalities, Button
and Input
components. You can read more on the composition on
React documentation page.
What is the actual problem we are trying to solve?
The actual problem is that we want ComponentNeedingProps
to be rendered in ThirdComponent
but it
needs data from the root component, App
to do so. In other words, ComponentNeedingProps
needs
data from somewhere higher in the Component Tree (App
) from where it is rendered
(ThirdComponent
).
The Solution?
The untamed powers of the children prop
You can compose components by making one a child of another, for example:
<ReactComponent1>
<ReactComponent2 />
</ReactCompoent1>
ReactComponent2
is invoked inside of ReactComponent1
and hence it is a child of it. Every
component has an 'automatic' prop named children
that holds the children of the Component. So
in ReactComponent1
we can write:
function ReactComponent1({ children }) {
return;
<div>
I render my children
{children}
</div>;
}
How can we use it in this case? Remember we want ComponentNeedingProps
to be rendered in another
component down in the Component Tree, if we can pass ComponentNeedingProps
as a child component
with the data it needs and then render it in its parent then we have successfully avoided prop
drilling.
So, we will have:
<ThirdComponent>
<h3>I am the third component</h3>
<ComponentNeedingProps content={content} />
</ThirdCompoent>
And in the declaration of ThirdComponent
we have:
function ThirdComponent({ children }) {
return (
<div>
<h3>I am the third component</h3>
{children}
</div>
);
}
This doesn't look much different from what we had earlier but wait for the magic.
By following this technique of rendering children, we can refactor App
to this:
function App() {
const content = "Who needs me?";
return (
<div className="App">
<FirstComponent>
<SecondComponent>
<ThirdComponent>
<ComponentNeedingProps content={content} />
<ThirdComponent>
</SecondComponent>
</FirstComponent>
</div>
);
}
Then we refactor each of the other components to render their children
.
FirstComponent:
function FirstComponent({ children }) {
return (
<div>
<h3>I am the first component</h3>;{children}
</div>
);
}
SecondComponent:
function SecondComponent({ children }) {
return (
<div>
<h3>I am the second component</h3>;{children}
</div>
);
}
ThirdComponent:
function ThirdComponent({ children }) {
return (
<div>
<h3>I am the third component</h3>
{children}
</div>
);
}
ComponentNeedingProps
stays as it is:
function ComponentNeedingProps({ content }) {
return <h3>{content}</h3>;
}
Did you see it? We have avoided prop drilling by giving ComponentNeedingProps
the data it needs
right from the source of the data App
and then by using the children prop, we passed it down to
where it should be rendered, ThirdComponent
.
Awesome. See the complete code:
When should you use the Context API?
You can also use the Context API to avoid prop drilling and I may write another article on that in the nearest future.
If you need to have some data accessible by many components at different nesting levels, then you should use the Context API. React docs advises that we 'apply it sparingly because it makes component reuse more difficult.' In other words, you might not be able to reuse your components 'out of context'.
That is it for this post, thank you for reading through. You can play with the code on CodeSandbox
Happy Coding.