Passing a value to a nested component using the React Context API
Tags: react, contextapi, storybook, wordpress
Published: 2022-07-13 19:14:49

---
title: Passing a value to a nested component using the React Context API
published: true
description: 
tags: react, ContextApi, Storybook, WordPress
cover_image: https://www.simpleimageresizer.com/_uploads/photos/4747af32/sigmund-B-x4VaIriRc-unsplash_1_1000x420.jpg
 
# Use a ratio of 100:42 for best results.
---

When I started learning React in 2018, hooks were not yet a thing. This was very taxing since I was struggling to get a component to render and having to pass props from parent to child added another level of complexity. 

Fast-forward to 2022 when I start playing in React again and I learn about the [React Context API] (https://reactjs.org/docs/context.html) during an interview.
 
<blockquote cite="https://reactjs.org/docs/context.html" >“Context provides a way to share values like these between components without having to explicitly pass a prop through every level of the tree.”</blockquote>

![chris pratt extending his hands from his temples outward with yellow line animation symbolizing his mind being blown](https://www.gifcen.com/wp-content/uploads/2022/06/mind-blown-gif-7.gif)

They make it sound so simple, but it took me a while to wrap my mind around it and use it in a meaningful way.

## Background
My company has a library of reusable React UI components, such as `Text` and `Button` that make it easy to test those components in isolation and later plug them into a product UI. 
  ![A simplified version of what I'm making](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zkc0zo3735cijlzj8b8r.png)

I am tasked with helping create a new password-less login flow using webauthn. The design has multiple cards, each with a header detailing a user's progress, a heading, and a link. Since this is a common design model it was decided to create a reusable component in our UI library so that it could be adapted for reuse in other projects.

## The Challenge
Since there is a component library, I will combine and modify existing components to create this new component. 

![The file hierarchy for this project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/34tm9iop0uajpg68w8tu.png)
 
I will use the existing `Surface` (background color) and `Text` components. I want to pair complementary text colors based on the selected background color. Since the background color will dictate the text color, I start with `Surface` and pass the background color to `Text` and finally into `Heading`. To do this I use React’s Context API to pass the data through the component tree, rather than having to pass props down manually at each level.

## How I did it
First I create a theme for my `Surface` component. The component library already had an existing theme, so I pull from those colors for this component-specific theme. Here I map through the different background colors and pair them with complementary text colors. 

```TypeScript
// Here I bring in the existing theme values to the surface theme
import { TextVariant, SurfaceVariant } from '../../types';

// Since this is TypeScript, I define the shape of my theme
export interface SurfaceTheme{
 variant: { [key in SurfaceVariant]: TextVariant };
}

// This is the theme with the color pairings
export const surfaceDefaultTheme:SurfaceTheme= {
 variant: {
  [SurfaceVariant.PRIMARY]: TextVariant.NORMAL,
  [SurfaceVariant.SECONDARY]: TextVariant.DARK,
  [SurfaceVariant.TERTIARY]: TextVariant.ACCENT,
 },
};
```

Next, I import `createContext`, a function of the React Context API from WordPress. Much like above, I create an interface for the shape of the context object and assign a variable to hold the context value.

```TypeScript
import { createContext } from '@wordpress/element';

// The shape of the context object
interfaceSurfaceContext{
 textVariant: TextVariant;
}

// Using createContext, I passed the acceptable value types and gave it a 
// default value of undefined
export const SurfaceContext =createContext<SurfaceContext| undefined>(
 undefined
);
```

Inside of my Surface function, I pull in the surface theme data (by way of the theme), assign a variable `variant` to props and give it a default value to use if none exists. Then I assign `contextValue` to hold the text color, and I pass that as a prop to my context provider. This is the top level of my component tree.

```TypeScript
export function Surface(props:SurfaceProps) {
// Get surface theme
 const {
  components: { surface },
 } =useTheme();

// Get the surface variant | assign to Primary
 const { variant = SurfaceVariant.PRIMARY } = props;

// Create an object with the text color
 const contextValue = { textVariant: surface.variant[variant] };

 return (
// Pass the text color to the React Context Provider
  <SurfaceContext.Provider value={contextValue}>
   <StyledSurface {...props} />
  </SurfaceContext.Provider>
 );
}
```

Moving into the first child component, `Text`, I import the `useContext` React Context function and my `SurfaceContext` variable from `Surface`. Inside of my Text function, I assign a variable to hold these values.  Then as a prop to the text component, I assign a series of values to the variant parameter.

```TypeScript
import { useContext } from '@wordpress/element';

import { SurfaceContext } from '../surface';

export function Text({
// params
// ...
variant
}: TextProps) {
	const surfaceContext = useContext(SurfaceContext);
...
return (
<Component
       // If the user explicitly passes a text color, 
       // that should be honored.
       // Otherwise use the text color from the surface 
       // theme if defined
       // Or, default to normal text color
	variant= {
	     variant || surfaceContext?.textVariant || TextVariant.NORMAL
} />
```

Finally, we reach the `Header` component, the whole reason for this endeavor. Since this component is made up of the `Surface` and `Text` components, there is nothing left to do here. All of the background color/text color information is received by its respective components and rendered correctly in this component. 

It's a little anti-climactic, but that's the magic of the React Context API: it just works. 

Here is the finished component in action:

![A walk through of the described component, showing different surface variants updating the text color](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihre5m5c8e3cthpdbp6l.gif)

I learn best by doing, so it took a real project to get me to fully understand the process. I describe it here mostly to solidify the concepts for myself, but maybe it will help you connect some of the pieces that you struggle with while using the Context API.

If you'd like some further reading on the subject, checkout these resources: 

- [React Context](https://reactjs.org/docs/context.html)
- [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html)
- [WordPress Element Package](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-element/)