Master Lists in React Native : A New Hope

Luke Brandon Farrell
ITNEXT
Published in
6 min readJul 10, 2019

--

Young coder… junior engineers, welcome to the list temple, here you will learn how to build perfect lists for your application. To become a React Native artisan you must master two things: lists and forms. Today you will master lists.

Lists are a hydra, they appear easy to master at first, you may even believe you can build one with a few lines of code, but don’t be deceived, they can grow many heads, and have unforeseen states to deal with.

Today you will learn the ways of the list, the various states a list can transform into, how you can conceptually model these different states to build error resistant lists which handle uncertain data, and achieve balance in your applications.

States of a List

When we mediate on building our lists, four states come to mind; empty, data, error and loading, but as we mediate further on these states, we come to the revelation that there is a greater model for our lists.

The image below represents the conventional model for lists.

Conventional List States in “Reward Me Now

It is correct that a list needs all these states, but the way we think about these states causes the problem; we think these states all belong in the same level of abstraction.

The truth is, that a list only has two states, with multiple sub-states. The two top level states of a list are data (data is available) and empty (data is NOT available).

We only have these two states, and not the error and loading states in the mix, because firstly we don’t want errors and loading to take prevalence over our data. Secondly there are multiple styles of error and loading states in our list, depending on if our data is available, we handle errors and loading differently.

Conventional vs. Enlightened Model

*The word data in this article refers to the state of the list when data is available. *The word empty in this article refers to the state of the list when data is NOT available.

Data (data is available)

The top level data state has the highest priority, if their is data available it will always be displayed in the list.

Your code may look like this:

if(!_.isEmpty(data)){ // We have data, always display the list
// Display List
<FlatList ... />
} else {
// Handle errors, loading when our list is empty

We don’t want errors with pagination, refreshing and interaction to halt the display of data in the list, and disrupt the user experience… that would be bad karma.

Items in List (data is available)

Errors

There are two types of errors which can occur in our list with data; network errors and processing errors. These errors can occur at multiple dimensions, they can occur for the full list e.g. a refresh error, or for individual list items e.g. deleted a single item and it caused a network error.

Network Error

A network error means that something went wrong at a API level; there is a syntax error in the API, there is no network connection, there was a server error. etc.

When data exists in our list we don’t want a network error to disrupt the display of data, in that case we need to show an alert to the user to notify them that the interaction they had with the list or item resulted in an error, without disrupting the list.

Network Error when their is data

Processing Error

A processing error occurs when a calculation in the list or item goes haywire and causes our application to crash, this can happen because data from the API can be uncertain, and any sort of computation with uncertain data can fail.

To solve this, we wrap the list with an ErrorBoundary and provide a fallback UI to prevent an application crash.

List Processing Error

Not handling these errors will crash your application, ruining your carefully crafted user experience, and disrupting the balance in your application.

Exception in our Item

Processing errors can also occur in our list items, and as masters of flawless user experience, we wouldn’t want those errors to crash our full list. We must also wrap each list item in an ErrorBoundary, this will have the benefit of allowing each item to handle errors independently.

A list where two of our items have crashed

Loading

When data is available in our list, the status of a network request should not affect the display of data, we can’t show a full-screen loading indicator every-time the user refreshes or paginates our list. In this case, we may want our list to show a loading indicator beside our data.

Refreshing List

This can either be a loading indicator for the whole list or individual items depending on the type of action the user has made.

The isRefreshing variable can be derived from existing data using this model (where isLoading is a boolean representing that X network request is in progress):

const isRefreshing = !_.isEmpty(data) && isLoading;

It is important that our loading state does not disrupt our data.

Displaying the data is always the top priority.

Feel free to add more states to this model, the most important thing to note is that data (data is available) is the top-level state to all those sub-states. Where empty (data not available) will have its own sub-states, as you will find out next.

Empty (data is not available)

When there is no data available we have more flexibility over what we can do with the page and display to the user. This usually consists of displaying a fallback which prompts the user to take an action. It is a good pattern to entice the user to take an action in these empty states.

No Cards Available (Empty State)

It’s important to note that for the empty state the error needs to take priority over our empty state, as if an error occurred in the network request, we can’t assume that the user has zero of X resource.

Error

There is no computation at the level of the list in the empty top-level state, so the only error available is a network error, this can come in many flavours; issue with the API (500), no permission (422), or no internet connection etc.

You can implement logic for displaying different UI based on the type of error; 422 -> prompt the user to login, 500 -> retry the request, no internet -> prompt to connect to internet etc.

We can add sub-states to this error state e.g. a refresh control, so the user can pull down this page and attempt to refresh as if it was a list. This sub-state will be empty -> error -> loading.

Using this model we can add sub-states to our states and build a user experience with greater depth.

Loading

This is the initial loading state of a list, the list is empty and it is loading. We can safely show a full size loader for the list, as nothing interesting has occurred yet.

Loading Indicator

This model can be extended in various ways, the main point is that it’s time we stop thinking in flat states for lists and move to a multi-dimensional state model if we want to provide elegant user experiences which spark joy in our users.

Enjoy these ideas? Checkout Part 2.

--

--

Luke develops mobile applications using React Native. He writes about component-first architecture and design, code readability, and React Native.