A useful pattern for handling remote data in React apps
By Devin Jameson on August 10, 2024
One of the most common things we do in React apps is display remote data fetched
from a server. Having worked on mostly React apps for the last several years,
I've seen this handled in several different ways and developed some opinions on
how to model and handle remote data state for maximum clarity.
First, let's take a look at a common approach. Can you spot the issues?
Here are the downsides I see:
We have to handle three different slices of state which can get out of sync
with each other and create impossible states. For example, we should never
be in a state where we have data and are loading data at the same time, but
this structure makes that possible.
It's possible, according to the type system, to end up in the final else
block of our component, which should never happen. This indicates poor
modeling of the state in our type system.
If we want our loading and error states to also be wrapped in a div with a
particular CSS class, we'd need to either repeat that container div three
times, pull out a subcomponent, or move the div into the parent component,
potentially impacting readability and ergonomics.
Now let's take a look at what, I think, is a more organized and clear approach
to managing this component's state. There are a few important things happening
in this revised component:
We introduce a RemoteData type, which is a discriminated union type. This
type enables us to represent our loading, error, and success states with one
slice of state instead of three.
We introduce an unwrapRemoteData function which enables us to convert any
value of the RemoteData type into a value of some other type.
Notice how there is no need to include a "finally" statement which resets the
isLoading state to false after our try-catch block because we can't possibly
be in a "loading" and "success" state simultaneously. Also notice that, thanks
to our unwrapRemoteData function, we can handle every state our component can
be in within a containing div, and without having to use if/else statements.
Hopefully this helps you improve the way you model remote data in React.