Thy Shall NOT Burn in the Context Provider HELL
How to structure your React PWA to achieve loose coupling of features and avoid the Context Provider Hell
In this article, I'm going to propose how to structure a React PWA in a way that not only achieves a loose coupling of responsibilities and SRP; but also streamlines the Context Provider definitions making it easier to work with.
Do you remember the Callbacks' Hell?
It looked like this:
You could go on forever nesting side effects of asynchronous actions in the Callbacks' Hell. Limitless. Painful. We moved past that situation thanks to two things:
- Promises
- async/await
That is undoubtedly good news for the dreaded JavaScript community. You know, the one that when it comes to math, 78% of the people are bad at it, and 32% are good.
But then React came along and took over Angular, bringing peace to the Galaxy and Context Providers to the index.js:
Does this remind you in any way to the Callbacks' Hell abovementioned? Indeed it does; this is just a new kind of Hell fired up by React's Context Provider pattern – which is a good pattern, by the way.
There must be some kind of way outta here
Said the joker to the thief
There's too much confusion
I can't get no relief
Bob Dylan – and later on Jimi Hendrix – knew what I'm talking about. This couldn't be it, and we must not add confusion on top of an already confusing world.
ForrestJS offers a small plugin library for Javascript and an ecosystem of ready-to-use packages that wrap famous third-party libraries into composable services.
When it comes to running a React App, it could be as simple as:
👉 Here you can find a comprehensive step-by-step tutorial that helps you run a React App with ForrestJS: https://forrestjs.github.io/howto/my-first-react-app/
Now let's dive deeper into how to structure Application Wrappers.
If you are in a rush, here you can find the complete and commented codebase:
What is a Context Provider anyway?
A React wrapper is just a component that receives a children property and renders it, among other stuff:
This wrapper simply decorates any children with a static title.
Not so valuable, right?
Let's look at a slightly more interesting Wrapper Component example and build an Authentication Provider:
The App Component will then be able to access the currently logged in user:
Getting out of Hell!
Now things get interesting. In a classic React App, you would do something like:
And you would slowly dig your grave into the ContextWrappers' Hell.
Thanks to ForrestJS, you can easily describe both App and AuthWrapper as a Feature:
Finally, in the App's index.js, we can compose our different pieces:
Here you find the complete codebase to this tutorial, heavily commented and ready to be forked and expanded:
Conclusions
With ForrestJS, we can transform nested Wrappers into linear and independently defined components for our Application.
Of course, this works best when you have multiple Context Providers, which is often the case.
Implementing a loosely coupled approach is essential and convenient if you are working on a large codebase or with a large team(s) organization.
The practical implications are:
- Minimize code conflicts because they can only happen in index.js when adding a new Feature
- Maximize independent work because developer Jane Doe will focus on her Feature folder, likely working in her Feature branch
- Maximize API-first approach because the interaction between Features happen as ForrestJS documented extension points