React’s safe Context API

Let your props go spelunking without guiding them ⛏

Published in
6 min readMar 8, 2018

--

Ever needed to pass a prop down through many levels of the component tree? Did you do it manually? It’s not ideal is it? Did it have to pass through components where it looked out of place?

The Context API solves this issue. It has actually been around for some time. It’s purpose is to aid with that specific scenario 🎉

But in older versions of React, you should not use it ⚠️

If you want your application to be stable, don’t use context. It is an experimental API and it is likely to break in future releases of React. — React docs

It’s was an experimental API with a multitude of warnings against using it. In many cases the docs suggested alternative solutions, avoiding it altogether or reconsidering your design choices. You can read about the drawbacks of the current Context API here 📖

The good news is there’s a new Context API as of React@16.3! And it’s much better 🙌

So, if you hadn’t heard of or used the Context API until now, there’s no need for FOMO 😅

For those in camp TL;DR, there is a new safe version of the Context API 🎉 It aids with providing context to components further down the component tree. Here’s a demo of a theme toggle using the new safe version that’s currently obtainable 👍

When would I need the Context API?

It’s hard to think of an array of scenarios in which you’d need to use the Context API. But those that spring to mind would be

  • passing through theming options
  • passing network activity status
  • passing locale information
  • passing user related metadata

If you have any other examples, please leave a response or a note and I’ll add them in 😉

Simple theming example

Let’s consider one of those scenarios. One simple example might be how we theme components lower down the component tree within our app. There are various ways to deal with this scenario. The simplest solution may be to change a class on the body element. CSS rules can then reflect theming changes. But in our scenario, we aren’t doing that. We’re being cool and doing the whole “CSS in JS” thing 😎

We will need to pass a theme prop down the component tree that components use to define their appearance.

Let’s consider a super simple Button component. It accepts theme and text as props.

The issue here is that we have to pass that theme prop down through every parent component. Even when using a state container such as redux we may still end up traversing many components.

How might we handle it currently?

There are ways we could currently handle this. The first is of course to pass that theme prop through every component in the component tree. Another way is to leverage ES6 and use the spread operator. It feels a little dirty but it does work.

A good thing about this technique it that we can define the props we care about. But we can still see that all the other props are being passed down the tree. It’s verbose enough and it’s easy to implement. In many cases it will probably suffice 👍

How might we handle it with the Context API?

The following implementation is based on what’s obtainable as of React@16.3.0 🤓

To use the Context API, we will create a Context. In our example we would create a context for theme. Something like

When creating a Context we pass a value parameter. This will become the defaultValue and the currentValue. It will likely be a good idea to use something like key-mirror here to create string constants.

In fact, you could take it a step further and create a module for each context.

The new context exposes a Provider and Consumer.

Providers

We can use a Provider as a wrapper to components that will need access to the current context value. Let’s consider a simple component that’s a page within an app.

Here, the ThemeContext Provider will pass its value to any Consumer that wants it. Currently, that value will always be day ☀️ which isn’t particularly useful 🤔

To update the value, we will use a prop on the Provider. This could be set with component state for example 😃

Here, we’ve just updated the component to have state for storing the theme value. We’ve added a button for toggling the theme.

How about updating that value from within a child component down the tree? It’s actually pretty simple. We can pass that setState function into the Context value. This may feel familiar to those who have used redux. We are making an action available on props.

You would then be able to consume and invoke toggleTheme further down the component tree 🎉

The Provider has some interesting possible uses. You can have many Provider instances. They have their own scope. For example, you may have a Provider higher up the component tree that is using the value day. But at the same time you could have a Provider lower down the component tree using night as the value. The lower Provider is not affected by the higher one even though they come from the same Context.

Consumers

It’s all good providing that theme value, but how do we consume it? We will need a Consumer. Let’s consider our Button component from earlier.

Updating it might look like this

The consumer will pass a render prop which is the current value for the Context 👍

How about if we changed our Button component to only provide children as a prop?

It’s not best practice but for the sake of demo we could also have the Button component bind its own onClick. As toggleTheme is available via context we can bind onClick to it within the component.

This way, it’s possible to pass actions down the component tree via the Context API 🎉

Much like Providers, you can have many Consumers within the component tree.

That’s it!

We’ve taken a brief look at what you can do with the safe version of the Context API.

I think it looks pretty sweet 🍭

Here’s the demo again just to show an example of what could be achieved!

As always, any questions or suggestions, please feel free to leave a response or tweet me 🐦!

Further reading

✉️ Subscribe to CodeBurst’s once-weekly Email Blast, 🐦 Follow CodeBurst on Twitter, view 🗺️ The 2018 Web Developer Roadmap, and 🕸️ Learn Full Stack Web Development.

--

--