Nested Context — The underrated aspect that’s probably missing from your React App

Nick Iannelli
3 min readAug 14, 2021

--

Read Time: 3 minutes

Before you begin, please note that this article is targeted towards more advanced React users. There is assumed knowledge that you are competent with React.

This article isn’t showcasing much code — it is here to get you to think about your own projects, and how this use for Context can potentially help solve your own problems.

Any search for React’s Context API will yield an endless stream of articles talking about using it as a state management tool. This is not one of those articles.

When I first read up about the Context API with the release of React 16.3, I immediately thought “Great, this solves my analytics problem!”. In modern front-end development, we are often tasked with having to have detailed analytics of a components usage. This could be something simple like deriving how many users clicked a link, or tracking events for how many people added a t-shirt to their cart. But as the web has grown, as has the data science behind it. And with the growth of the data science, the need for more narrowly focused data has grown too.

One such example is an add to cart button. As a developer, it makes sense to build a separate component to add a product to the users cart, which can know the business logic behind whether it’s disabled, or if it defaults to an “Add to favourites” button if the item is out of stock. Or if it is a “find a store” button when you can purchase it in store only. All things that businesses can ask for.

In this scenario, this data (assuming it is a large eCommerce site) would live in a state management tool such as Redux, and the button could connect to the store instance to work out what the correct state to display is. Great! We can display this button on a product grid page, in a modal, on the product page, on the recommended products, you may also like, bought-bought, in a carousel! Everywhere! It’s eCommerce and we need to sell!

Along comes the analytics problem.

“We can see add to carts for the t-shirt, but we really wanna know what is working best!”

It starts with a request. Seems simple enough. An easy one to tackle. We’ll just add a prop to the component for renderedBy="productGrid", and log an analytics event there. Except it’s not directly rendered by the grid. It’s rendered by a ProductCard that’s rendered by a Grid that’s rendered by a ProductGrid. All of a sudden we’re passing around a renderedBy prop to everything.

Thankfully, Context was born.

Quick snippet and a question — what gets rendered out to the DOM here?

import React, { createContext, useContext } from 'react';

export const AnalyticsContext = createContext({
category: 'Page'
});

const ButtonInCtx = () => {
const { category } = useContext(AnalyticsContext);
return <button type='button'>Context: {category}</button>;
};

export default function App() {
return (
<AnalyticsContext.Provider value={{ category: 'Page' }}>
<AnalyticsContext.Provider value={{ category: 'Header' }}>
<ButtonInCtx />
</AnalyticsContext.Provider>
<AnalyticsContext.Provider value={{ category: 'Body' }}>
<ButtonInCtx />
</AnalyticsContext.Provider>
<ButtonInCtx />
<AnalyticsContext.Provider value={{ category: 'Footer' }}>
<ButtonInCtx />
</AnalyticsContext.Provider>
</AnalyticsContext.Provider>
);
};

If you’ve read the rest of the article it’ll probably be a pretty simple guess.

An example showcasing nested context. Shows 4 buttons labelled as “Context: Header”, “Context: Body”, “Context: Page” & “Context: Footer”

Nested context.

When you nest a context provider inside a context provider of itself, you can override the previous context.

When setting up your React application, you can give your layout sections different names, and use those names within consuming components.

Better yet, your context consumer can be a context provider. Take the above example, and consider how this would look:

const CarouselProvider = ({ children }) => {
const { category } = useContext(AnalyticsContext);
return (
<AnalyticsContext.Provider value={{ category: `${category} - Carousel` }}>
{children}
</AnalyticsContext.Provider>
);
};

The usage of Context goes much deeper than a replacement for state management. Using it as an analytics provider is just one of the many uses for this underrated tool.

--

--