Eliminating Prop Drilling with React Context: An In-Depth Guide

VasanthSelvaraj
3 min readFeb 13, 2023

React is uni-directional in the sense that data flows in a single direction, from the parent component to its children components, through the use of props. In React, the parent component is responsible for providing the props to its child components, and the child components can access the props passed down to them but cannot modify them directly.

This uni-directional data flow makes it easier to understand the flow of data in a React application, especially in large and complex applications. It also helps to enforce the principle of separation of concerns, as each component only has access to the data it needs to render, and does not need to worry about the data in other components.

While the uni-directional data flow in React has many benefits, there are also some potential drawbacks that should be considered one of them is :

Limited Flexibility: The uni-directional data flow can also limit the flexibility of an application. For example, if a child component needs to share data with a parent component, it must do so indirectly, typically by calling a callback function passed down from the parent.

For example, consider a scenario where you have a component that needs to access a value that is stored in a parent component several levels up in the component tree. To access that value, you need to pass it down the component tree as a prop at each level. This can result in a long chain of props that make it difficult to understand the flow of data through the component tree.

Here’s an example of prop drilling:

function Grandparent(props) {
const [value, setValue] = React.useState("Initial value");
return (
<Parent value={value} setValue={setValue} />
);
}
function Parent(props) {
return (
<Child value={props.value} setValue={props.setValue} />
);
}
function Child(props) {
return (
<div>
<p>{props.value}</p>
<button onClick={() => props.setValue("New value")}>
Change value
</button>
</div>
);
}

In this example, the value and setValue functions are being passed down the component tree from the Grandparent component to the Child component, resulting in prop drilling. This makes it difficult to understand the flow of data through the component tree, especially in large applications where there are many levels of components.

React Context can be used to prevent prop drilling by making data available throughout the component tree without having to pass it down as props. Here's an example of how to use React Context to avoid prop drilling:

import React from "react";const ValueContext = React.createContext({
value: "Initial value",
setValue: () => {}
});
function ValueProvider({ children }) {
const [value, setValue] = React.useState("Initial value");
return (
<ValueContext.Provider value={{ value, setValue }}>
{children}
</ValueContext.Provider>
);
}
function Grandparent() {
return (
<ValueProvider>
<Parent />
</ValueProvider>
);
}
function Parent() {
return (
<Child />
);
}
function Child() {
const { value, setValue } = React.useContext(ValueContext);
return (
<div>
<p>{value}</p>
<button onClick={() => setValue("New value")}>
Change value
</button>
</div>
);
}

In this example, the ValueContext is created using the React.createContext method, and the ValueProvider component is used to provide the context to the rest of the application. The Child component uses the React.useContext hook to access the value and setValue functions from the ValueContext.

By using React Context, the value and setValue functions are made available to any component in the application, without the need for prop drilling. This makes it easier to share data between components, and reduces the complexity of the application.

--

--