Sat Mar 20 2021·5 min read
Photo by Roberto Nickson
Years ago I used global state management libraries like
redux to handle most
(if not all) of the state in my application. I used to put all kinds of state in
the redux store - i.e.:
Obviously I was using redux wrong, I wasn't supposed to put form state or other local state into the global redux store, but I didn't know at the time.
It was way more difficult back then to manage state, without the ease of abstracting logic and the code reusability that hooks bring. It kind of made sense to just put everything in the global state. I didn't have to think about it - I could just access the state from anywhere inside of my application, I didn't have to prop drill or lift state up to a common parent.
However the way I was using redux came with some drawbacks too - mainly lots of
boilerplate, indirection, complexity grew as the application grew. Most of the
state I was pretending to be
global was not actually global. In fact in most
applications the truly global state is so little that it would be simpler to
manage it using react context.
State is data that changes over time.
The user has control over the data that changes in the client state (i.e. language preference, theme preference, modal state, side menu state, form input values), but they don't have control over the async data on the server (which can be changed by multiple users at the same time).
We can separate state into 2 main types: Server State and Client State.
server state is asynchronous state that's stored on the server (i.e.
products, orders) - we cache it on the client for performance reasons. It
decreases the load on our database and the users have quicker response times and
see less loading spinners.
If the state is stored on the server it's not client state, it's server state. This is data that the end user doesn't own and control (can be changed by multiple users at the same time).
client state is synchronous state managed in the browser, lost on page
reload, lives in memory. It is data that the user has control over and it can
only be changed by the user locally.
If the state is only maintained on the frontend, it's Client state.
Client state can be further separated into
Local Client State and
Global Client State:
Local state is UI state that is used in a single or few components that are colocated (they're not spread in completely different places throughout your application), i.e.:
Global state is used for data accessed from different parts of your application and kept in sync between the different components that access it.
It would be a hassle to initialize a language in your
App component and then
pass the language all throughout your application, this is where global client
state comes in.
This data doesn't come from the server. A common exception being the current authenticated user, which is often stored in global state(it's not very common that you perform the full CRUD (Create, Read, Updated, Delete) cycle on users).
Examples of Global Client state are:
The boilerplate and complexity you'd have to add to your component to manage
local state in your global state, paired with the fact you're not
actually getting anything out of it, makes for an easy decision. Just leverage
react's default state management hooks -
managing local client state.
When you keep server state (async data from the server) in the global state, you have to expect that this server state can change because it can be mutated by multiple users at the same time.
Once changed your global state would be out of sync with the server, so it's not
the same, neither is it as simple as the
isDarkMode boolean global state,
which can only be changed by the user currently browsing your site. That adds a
lot of complexity and things you have to think about, i.e.:
As a developer I want to leverage a package that will solve these problems for
me, so I don't have to implement a solution myself. Right now there are 2 main
libraries in the react ecosystem -
swr. My personal preference being
react-query, for reasons I'm not going to get into right now, but you can
check out this comparison table.
Until recently you had two options for managing server state:
Both solutions introduce a lot of complexity to any application that relies on server state and is not super small. Both solutions don't help you implement any of the optimizations mentioned above.
Do you have enough global state that you can't intuitively manage using react context. For most applications the answer will be no. Unless you have some very complex analytics dashboards, etc, the truly global state in your application could be comfortably kept in react context.
You have to use the right tool for the job, i.e.
redux, if you have lots of
truly global state that you couldn't easily manage with
context (which is
very rare), use
react-query for your server side state, and manage your
local component state with