React sub-components Part 2: Using the new Context API

Further simplifying the sub-component pattern using contexts to make flexible, easily testable and reusable React components

Maxime Heckel
Apr 16, 2018 · 5 min read

A more accessible, readable, mobile-friendly and up to date version of this story is available on my personal blog!

To fully understand this post, please read my original post about React sub-components first.

I’ve received a lot of good feedback after publishing my first article about React sub-components, however, some of them got me thinking about how I could further improve the sub-components pattern in order to make it easier to read and use.

The flaws of the current pattern

  • Having to import findByType for every component using sub-components is annoying
  • It is hard to compose or extend a sub-component to handle specific cases
  • It’s not the most readable
  • We could easily put the wrong data within the sub-component, it is not aware about what we’re trying to render within it

While I agreed with all these statements, I couldn’t find an elegant way to address them without making the component difficult to use. However one day, one user from the Reactiflux community mentioned that using contexts would remove the necessity of using the findByType util within each sub-component; which obviously got me curious. Moreover, I was hearing a lot about the upcoming new Context API in React 16.3.0 and I thought that this would be a great way to start experimenting a bit with this new functionality.

What is in the new Context API?

The new API, however, takes a new approach to contexts and makes the feature more accessible. It is available in React 16.3.0, you can read a lot more about it and how to use it in this article. For the purpose of this post, I’ll just keep it short and explain the 3 main items that make up this new pattern:

  • React.CreateContext: a function that returns an object with a Provider and a Consumer
  • Provider: a component that accepts a value prop
  • Consumer: a Function as Child component with the value from the Provider as a parameter

With these new items, we’ll see that it is possible to create a better sub-component pattern that answers all the flaws stated in the first part.

How to build a sub-component like pattern with the context API

In order to achieve this, we’ll need to create an ArticleContext. This will give us an ArticleContext.Provider component that will be our main parent, which we’ll rename Article, and an ArticleContext.Consumer, which will help us build all the sub-components we need.

Let’s start this example by implementing a Title sub-component:

Article.js

The example above shows how we can leverage Consumers and Providers to obtain the same sub-component pattern as we had in the first example of my previous article. If you compare this code in the link with the code above, you can see that the latter feels way simpler. Indeed, thanks to the new Context API, there is no need to build and use the findByType util. Additionally, we don’t rely on the displayName or name property of the sub-component to know how to render them.

In the code below, we can see that the resulting Article component is much easier to use. Instead of passing children to the Title sub-component, we just need to pass them in the value prop of Article, which will make them available to every Consumer of the Article context (i.e. to every sub-component defined as a Consumer of this context).

App.js

Moreover, if we want to wrap Article.Title in another div or component, we can now do that as well. Given that the implementation of the findByType util in my first post was relying on the direct children of Article , sub-components were restricted to be direct children and nothing else, which is not the case with this new way of doing sub-components.

Note: You can see above that my value object passed to the provider is set to the parent’s state. This is to avoid creating a new object for value all the time which will trigger a re-render of Provider and all of the consumers. See https://reactjs.org/docs/context.html#caveats

Additionally, we can make the piece of code above look even better. By simply exporting the Title functional component in Article.js we can give up the <Article.Title/> notation and simply use instead <Title/>.

App.js

This is purely aesthetic though, and I personally prefer the first implementation. It gives more context about where a given sub-component comes from and with which parent component it can be used, and also avoids duplicated name issues.

Caveats

Full implementation

  • The full Article component code and all its sub-components in Article.js
  • An example App.js where you can see how we use the full component and sub-components
Article.js
App.js

If you feel like playing with this pattern I’ve made the example of this article available on Github here, you can set up the dockerized project using docker-compose build && docker-compose up, or just run yarn && yarn start if you want to run it directly on your machine.

If you liked this article don’t forget to hit the “clap” button and if you have any other questions I’m always reachable on Twitter, or on my website. You can also subscribe to my Medium publication to not miss my next post.

Maxime Heckel

Software engineer and space enthusiast.