react

2022/01/09

Take Care with Providers

How often do providers cause a re-render? Here's why wrapping your entire application with a provider is a bad idea.

Author: Tristan Brewster

The default view for Create React App

The React Context API, introduced a few years ago, provides an easy way for you to avoid the explicit passing of props to child components.

The idea is simple. One component (component A), higher up in the tree, contains a lot of information that many components throughout your application will need. Instead of requiring you to manually pass all of this information via props (which can quickly become more tangled than spaghetti), you can share this information via Context: the API that allows child components of component A to have implicit access to this information.

The API is only slightly more complicated than the idea. You implement the useContext hook, create a Provider, and wrap a part of your application.

There are a variety of online examples. If you want an example of how providers look under the hood, see useSettings.

Notice how I emphasized "a part of your application." This is important, and the topic of this article.


React, at its heart, is a library meant for managing a tree in a predictable, efficient fashion.

That's really—skipping an implementation detail or two—what it exists to do. This is why we have both React Native and ReactDOM. They both tap into the tree that React itself provides and render content depending on the platform they're targeting.

To really drive my explanation, I'll first briefly explain what a tree looks like.

Recently, we released a project called Tree. As the name suggests, it's a lib meant for managing a tree-like data structure. This is an example of what the internal data looks like:

A JSON object showing a 'root' object with two children nodes: 'child-1' and 'child-2'

So now, let's consider what happens when we want to modify the root object. Since both child-1 and child-2 are within the root object, changing anything on root inadvertently updates its children.

This behavior is very similar to React's concept of rendering.

In most React projects, the top-most component is probably <App />, or something just like it. Think of <App /> instead like <Root />. If you change the state within App, React has no choice but to re-render it, causing a re-render of all children components.

I've built a simple demonstration of this effect. Head over to ytdmv.csb.app and open the console. If you click the "Increment" button, you'll notice that this causes a re-render of both App and Card.

So... where do providers come in?

The Provider Allure

Providers, obviously, are very useful. There are tons of libraries exporting all sorts of providers. You may even have one or two yourself! The problem is that most libraries tell you to wrap your App in their provider, giving literally every child component access to the context it provides.

As I've demonstrated, any parent component will re-render all child components if either its props or its internal state changes from the previous render.

This is precisely the danger. Not too many newer React devs understand that providers are themselves React components, and therefore any change within it can (and probably will!) re-render your entire component tree.

The Point

My main point in this article is not to discourage the use of providers. I use them daily. Instead, my goal is to get you to have more care when you use providers, and more importantly, where you place them.

If your /users page, for instance, is the only set of components that needs X provider, then only wrap that area! That way, you can reduce as many unnecessary re-renders as possible.


Take care with providers.

End of Line.

Infinium

Building and maintaining the future of open-source.

Contact us
Copyright © 2021 Infinium LLC. All rights reserved.

This website is open-source.

Made with in Salt Lake City.