Slaying a UI Antipattern in React

Solving a well known a UI problem with React

A. Sharif
JavaScript Inside


The following write-up is based on Stefan Oestreichers blog post Slaying a UI Antipattern in Fantasyland which was originally influenced by Kris Jenkins excellent how Elm slays a UI antipattern.

Just a quick overview of the anti-pattern we’re talking about here. Typically you might see data represented like the following i.e.:

const data = {loading: false, errors: null, items: []}

Here’s how this is described by Stefan Oestreicher:

But of course it’s easy to forget to check the loading flag or maybe you just can’t be bothered right now because of time constraints and “will do it later”. It also just makes for awkward code everywhere. Setting the items to null instead of an empty array creates even more problems so that won’t help either.

Stefan Oestreicher, Slaying a UI Antipattern in Fantasyland

So we have to manually keep track of the current data status, making sure we don’t forget to set the correct loading, error and data state. It’s very easy to forget to set the loading to true to false, if you think about it. Forgetting to keep the state in sync leads to a false representation in the UI.

In Slaying a UI Antipattern in Fantasyland we are represented with a different way to think about the problem:

type RemoteData e a
= NotAsked
| Loading
| Failure e
| Success a

We might have different states to represent in the UI, i.e. NotAsked (we haven’t done anything yet). By modelling all possible states, we can resort to using daggy f.e., which enables us to handle the possible outcomes.

const RemoteData = daggy.taggedSum({
NotAsked: [],
Loading: [],
Failure: ['error'],
Success: ['items'],
// in our constructor
this.state = { items: RemoteData.NotAsked }

(* Taken from Slaying a UI Antipattern in Fantasyland)

By now we should have good low level idea on how to solve this anti-pattern.

<Loader />

What if we could take all these ideas and wrap them inside a React component, which takes care of all of this, without having to manually take care of the low level stuff.

Michael Jackson wrote about the render-props concept in his Use a Render Prop! post. In short:

A render prop is a function prop that a component uses to know what to render.

More generally speaking, the idea is this: instead of “mixing in” or decorating a component to share behavior, just render a regular component with a function prop that it can use to share some state with you.

Michael Jackson, Use a Render Prop!

So we can pass in a function via a defined prop and access any needed values to render the needed outcome. Now, what if we could leverage this concept and define multiple props?

What if we could define a render prop for every possible state for our previously defined remoteData structure? Let’s see how we can approach this concept with a high level example.

So we defined a specific render prop of every possible outcome. Now we don’t have to think about if the UI is representing the proper state, all we need to do is tell <Loader /> what we want to see if the component is loading, has an error and has any data.

Now that we have an idea of how Loader should work, let’s implement the functionality.

As we can see, we don’t need too much to have a full functioning Loader component, that can be configured via render props.

Check the full implementation.

Check the demo.

If anyone is interested in turning this it into a library please free to do so!

Update: Use react-remote-data by Jack Franklin!

If there are better ways to solve these problems or you have any questions, please leave a comment here or on Twitter.



A. Sharif
JavaScript Inside

Focusing on quality. Software Development. Product Management.