Skip to main content

Command Palette

Search for a command to run...

Handling global state in React without Providers and boilerplate

Published
2 min read
E

Startup Founder | Senior Platform Engineer @ A.Team | Building and Deploying Scalable Web Applications

ReactJS has a built-in way to handle "global" state - React Context. However, after using many contexts I realized I am typing a lot of boilerplate code and getting to a "Provider hell". I had to nest Provider after Provider in my root App component to ensure that all the children had access to it. For a simple example - let's construct a changable theme context. First, we need to create the type of the context (this article assumes usage of typescript). Let's have the type be similar to the return value of useState - so [theme, setTheme]. Then, we need to create the context, and pass it an initial value. The second (setTheme) element of the tuple is unnecessary, but we still have to do it. Then we need to create the provider, which takes children as props and passes them down the tree, while creating the theme and passing it to the ThemeContext.Provider component. The entire code of that file looks like this.

context-theme.png

Then we have to go to a component close to the root of our tree and add the Provider there, next to many other providers (if the project is big enough).

Facing the need of "state-like" contexts, I decided to give it a different solution. I built a createStateHook function which keeps the state in a closure and returns a hook that uses that state and rerenders when the state changes. I used the "magic" of rxjs for this to make the code shorter, but it's entirely possible without using rxjs dependency.

create-state-hook.png

Now we can create the theme in a much easier way. We only need the type of the theme, and to call the createStateHook function with the initial value.

create-state-hook-theme.png

There is no need to add a provider at a higher level. useTheme hook will work anywhere, and when the theme is changed - all the components that use useTheme will be rerendered.

For global values that resemble the shape of "state" (which is a lot of them), this approach is far more concise. We converted code from ~20 lines + a Provider in the root component to 2 lines without a provider.

N

Check out Elf

E

In my “quest” to building a great state management solution I tried playing around with observables and operators as well. While not as sophisticated as Elf, I had a simple state management with the idea of “useObservable” hook. But in this particular case I tried keeping things as simple as possible. The user of the func doesn’t even know that the state is a BehaviorSubject - using Rxjs is an implementation detail. I have the same func implemented without Rxjs, it was just easier for the article.