Skip to main content

Command Palette

Search for a command to run...

From Roots to Branches to the Leaves: Growing with useContext

Like roots nourishing branches and leaves, useEffect connects your component to the outside world. It helps React apps grow by handling side effects.

Updated
5 min read
From Roots to Branches to the Leaves: Growing with useContext

In our last article, we discussed gardening — how specific conditions are required to plant a particular type of plant, just as useEffect helps React components respond to changes in their environment. Some plants require daily water intake, while some require weekly water, and others only require it once.

Imagine a huge garden with 4–5 trees, some plants, and grass spread all around. Now, think about watering it — but with a twist. Instead of pouring water directly at the base, you can only water from the top, say, the leaves. The water droplets then have to pass downward — from leaves to branches, branches to the stem, and finally reach the roots. But here’s the problem: this method of watering can lead to a loss of water in both quality and quantity. Since the droplets take time to flow through the plant’s veins, they can deteriorate due to external factors (like sunlight evaporating them) or internal factors (like leakage along the way).

The same thing happens with props in React components. When data is passed down through multiple layers, it can get messy, harder to track, and sometimes even lose relevance by the time it reaches the component that actually needs it. This leads to a very fascinating term - prop drilling!

Imagine we have a Plant component that holds everything the plant needs: Water, Sunlight, Chlorophyll, and Minerals. The Plant component passes these props to its child component Trunk. The Trunk passes them further down to Branches, then Leaves and Roots. Finally, this can even go deeper into the Soil layer.

Here, each component has to carry the same props — even if it doesn’t directly use them — just so the next layer can get access. This is the exact problem with prop drilling.

“In React, prop drilling refers to the process of passing data from a top-level component down to deeply nested child components by passing props through every intermediary component, even if those intermediaries don’t directly use the data.”

It happens because React only allows data flow top-down (unidirectional) via props.

So how do we curb prop drilling? How do we ensure props are managed in a cleaner, more organized way while preserving the originality and essence of our data inside React components? The answer lies in React’s useContext hook, which allows us to share state seamlessly across the component tree without the hassle of manual prop passing.

Let’s circle back to our gardening parallel. Earlier, we imagined water flowing strictly from the top down through the plant, but that’s not how nature really works. In reality, when the source of water—be it a sprinkler or rainfall—appears, every part of the plant engages with it directly. The leaves soak it in, the branches get refreshed, the stem absorbs it, and even the soil drinks from the same source. Everything connects straight to the origin, without relying on a single pathway.

React mirrors this behavior with a central store. Instead of forcing props to drip down layer by layer (like our earlier top-down flow), we set up a single source of truth—using tools like useContext —where data lives at the origin. Just like the garden, every component can directly tap into that source whenever it needs nourishment.

The next big question is: how do we actually build this store? How do we access it, and how do we make our components consume the data from it? This is where React’s useContext hook comes into play. Let’s start by looking at the basic syntax of useContext and how we can use it across different components.

  1. We inject the context into our React components by using -

    import { createContext, useContext } from "react";

  2. Then we create our context -

    const ThemeContext = createContext();

  3. Wrapping our components with the Provider, which would help us access the context -

    <ThemeContext.Provider value={theme}>

    <Layout/>

    </ThemeContext.Provider>

  4. And later on in the child components, use the context created.

    const theme = useContext(ThemeContext); return

    Current Theme: {theme}

When you went through the points, a bunch of questions must have spiraled through your head: What is a Provider? What is a store? What are createContext and useContext?

When we talk about createContext, think of it as setting up a water tank for our garden. It’s the container where our shared data—the water—will live. By itself, the tank doesn’t water the plants, but it defines the store, the single source of truth for our data.

Next comes the Provider. This is like connecting a sprinkler system or opening up the rain clouds. The Provider’s job is to distribute the water (data) to every plant (component) within its reach. Any part of the garden under the sprinkler is now able to receive nourishment.

Now, here’s where useContext comes in. Each part of the plant—be it the leaves, branches, stem, or even the soil—directly absorbs the water falling on it. Similarly, any React component under the Provider can call useContext to directly access the data from the store. No middle layers are needed to pass water around, just like no unnecessary prop drilling is required in React.

ConceptGardening AnalogyReact Functionality
createContextWater tankCreates a store to hold shared data
ProviderSprinkler system / opening rain cloudsDistributes data from the store to all nested components
useContextThe plant absorbs water directlyComponent directly consumes data from the store without props

It might seem a bit overwhelming at first, but as we dig deeper, you’ll discover just how powerful and organized it makes your React components. In our next blog, we’ll roll up our sleeves, create a live store, and show how to effortlessly share its data across multiple components.