React: Stacking Context
Tags: react, javascript, webdev
Published: 2020-04-08 08:46:41

Just the other day, I encountered an unusual challenge when working with the React Context API. I’m eager to share what I learned and how I worked around the restrictions that it has.

![Photo by [Claudia Wolff](https://unsplash.com/@kaimantha?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/12032/0*i4sdL1zRaKIFLYpb)

---

# Scenario

Take a look at the following simplified code snippet:
{% gist https://gist.github.com/Chroma91/25049cb0cf9a9eee52a14800d52152cc %}

The context’s value is dependant on the `name` prop. That means the values for `outer_context` and `inner_context` differ.

---

# Problem

The most inner component `ComponentThatUsesContextFromBothProviders` needs the values of both context providers it is wrapped in. However, by default, it is only possible for us to get the context of the closest provider, which would be `inner_context` in this case.

First things that might come to your mind now are:

**Pass the value of the outer context as a prop to the inner component**

We don’t want to do that because we would end up with prop drilling again in more complex scenarios where we would need to pass it down the whole tree. The React team introduced the Context API to prevent precisely that.

**Use some kind of state management**

We don’t want to overcomplicate things with state management since our use case is straightforward, and we don’t want to pollute our global state. Only the components wrapped inside of the context providers need to know their values.

---

# Solution

**Finding a leverage point**

The value of our context is dependant on the `name` prop we set for the provider. That means the context that is computed for each name should be different. We know that we might need all of the individual key/value pairs when a component is wrapped inside of multiple providers.

---

**How does that help us?**

Oversimplified our structure needs to look like this to provide that functionality:

```
outer_context -> Component A -> inner_context -> Component B

Component A Context = { outer_context: 'outer_value' }

Component B Context = {
  outer_context: 'outer_value',
  inner_context: 'inner_value'
}
```

Maybe you did already see where I’m heading with this. As the title of this article suggests, it makes sense to stack our context in that case. If we now introduce a new component `C`, it needs to have all the context of the component `B` plus the new context that is provided.

---

**How can we achieve a stacking context?**

It’s just a few lines of code as seen in the following snippet:
{% gist https://gist.github.com/Chroma91/ba2dc30425e40365f4bf8dbfcf270f2a %}


There’s no magic involved. Instead of saving the context’s value directly, we create an object that is indexed by the `name` prop in this example. Every context provider now only needs to use the existing context and ‘push’ it’s own value to the stack. Now we can get the values like this:

{% gist https://gist.github.com/Chroma91/c5ce40fcfb33ccc16ca212a5ec41e165 %}

You can also create a custom hook to make it more convenient to get the value and handle the case of a non-existent key.
{% gist https://gist.github.com/Chroma91/5939797466a1935124de7bd1e5bd2c52 %}

---

# Conclusion

Sometimes it makes sense to ‘bend’ the React world a bit and break out of the boundaries set by it. Do what fits best to the scope of your project. Just remember that everything is just JavaScript in the end. ;)