by Jake Moxey
Introducing React Loads — A headless React component to handle promise states and response data
Simple, declarative, and lightweight
Background
There are so many methods to handle state in React right now. From local state to Redux, the new React Context API and new libraries such as Unstated and Copy Write. All these methods have great use cases, and there are no absolutes in which I’d drop one entirely in favour of another. Each of them have their situational benefits.
But I don’t want to get into the nitty gritty of React state management. Check out Kent C. Dodd’s excellent article about Application State Management for that.
Though I do want to touch on the case of handling loading and response state from a promise, for example HTTP requests and resource fetchers. A promise has three explicit states: pending, resolved, and rejected. It has the additional implicit state of idle, when the promise has not yet been triggered.
How is promise state managed in React?
It can be managed in local state through something as simple as an isLoading
variable to reflect the “pending” state. response
and error
variables are then used to reflect the “resolved” and “rejected” states, respectively.
It can be managed in a Redux store through actions such as GET_DOG_REQUEST
, GET_DOG_SUCCESS
and GET_DOG_ERROR
. These then could map to respective isLoading
, response
, and error
variables in the store.
Managing promise state can be dangerous, hard to read, and have problematic UX!
- Nested ternaries in your
render
function can get difficult to interpret and messy, and can therefore be prone to errors. Here is an example of such a problem:
From this example, it is not clear that !error && !response
implies the “idle” state. It is also unclear that the else
section of the isLoading
ternary implies that the section has been loaded or errored. And just imagine managing more than one promise and their respective states! Urgh.
2. Seeing flashes of “loading” state in your UI is annoying. When a promise goes from an “idle” state to a “pending” state, this state change should be reflected in the UI with a loading indicator. However, it’s possible that your promise will resolve in a minuscule amount of time causing your user to see a “flash” of loading state. This is something many developers are not aware of when they handle promise states.
3. Solely managing promise states in Redux is unnecessary. When Redux was first released, it was common for developers to transfer the majority of their state into a Redux store. However, creating three actions for a promise state, then creating three reducer cases for those actions, causes unnecessary bloat in your application. I’m guilty of this too — but no longer! Actions to handle response/error data are sufficient in my opinion.
Avoid handling promise state in Redux.
Introducing React Loads
React Loads aims to solve the above issues in a minimalistic fashion. The user provides the <Loa
ds> component with a function that returns a promise. It will return its
state and re
sponse data as
render props.
jxom/react-loads
react-loads — A simple React component to handle loading stategithub.com
Declaratively handle promise state and response data
React Loads provides you with render
props to load the promise. This also handles its state and response data. You can get it to load the promise when the component mounts by passing the loadOnMount
prop to <Loa
ds>.
Predictable outcomes
Using state variables such as isIdle
, isLoading
, isTimeout
, isSuccess
, and isError
from render
props will make your render
function predictable and easy to read.
Removes the “flash” of the loading state
React Loads doesn’t transition to the “loading” state until 300 ms after the promise is triggered. It will wait 300 ms for the promise to hopefully resolve before it goes into a pending state. This time can be modified using the delay
prop for <Loa
ds> .
Ability to cache response data
React Loads has the ability to cache the response data on an application context level. Once the data loads from an invocation of fn
, it will use the response returned from the promise for the next subsequent invocation’s response
. The newest data will then load in the background, skipping the isLoading
state, and update response
accordingly. You can enable caching by adding a cacheKey
prop to <Loa
ds> . Read more about caching here.
Final remarks
We’ve been using React Loads in production at Medipass on our patient and practitioner facing web app for the past couple of months. It has made our developing experience really easy. We’ve been able to remove a heap of code that handled promise state and response data, and just let React Loads do all the dirty work.
Consider using it in one of your projects and let me know how it goes! If you have any suggestions or spot a bug, feel free to raise a PR (or an issue) on the repository!
Thanks for reading!
Follow me on Twitter and GitHub (I’ll follow you back I promise).