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.
Scenario
Take a look at the following simplified code snippet:
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:
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:
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.
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. ;)
Top comments (0)