Loading State Trick for Stateless Functional Components in React

I want to share with you a little trick I’ve been using lately with stateless functional components in React. This is probably really old news to some of you, but I’m hoping there are a few of you who don’t know this one yet.

If you’re getting started with React, and especially if you’re using Redux, you’ve probably come across the concept of container and presentational components.

Container components provide data to nested components. These components will generally use lifecycle methods, such as componentDidMount, to fetch some data and pass it down.

Presentational components, on the other hand, are used solely for displaying data passed into them and generally do not use any lifecycle methods. Often, if a presentational component does not require any lifecycle method (other than the required render), then this component is written as a stateless functional component.

A stateless functional component is simply a function that returns the markup (React functions or JSX). Props are passed as arguments to the function, and then utilized within the markup. Let’s make a simple example of a stateless functional component that expects an array of items, and displays each one of those items.

import React, { PropTypes } from 'react'

const DisplayItems = ({ items }) => (
  <div className='items'>
    { items.map((item, index) => <div className='item' key={index} {...item} />) }
  </div>
)

Display.propTypes = {
  items: PropTypes.array
}

export default DisplayItems

I hope the ES6 doesn’t scare you. I’ve created a function called DisplayItems. This function expects a props object as an argument, and I’m using ES6 destructuring to make it clear that I’m expecting and will use an items property on the props object.

Then, I am using the implicit return feature of ES6 arrow functions to return the markup (in this case JSX, it’s all I really use) from within the body of the function.

Then, I map over each item, returning another div. React requires that we add a key attribute to items that are dynamically populated, which is often the case with displaying arrays. In this case, it was easy to use the index, but it might be more useful to use a property on the item itself in your case.

Lastly, I am using ES6’s Object spread syntax to pass all props from item into the div. In your example, it is possible that this inner item div would be another presentational component that needs access to all the props on item.

Thus, if we used this in our app, regardless of how many items we pass to this stateless functional component, React would give us the wrapping div, and then any divs generated by the map function.

But what if you currently don’t have any items and you don’t want to display the wrapping div until you have items?

It is possible to reconfigure this component to display alternative markup if there are no items to display.

Imagine that I have built another component called LoadingSpinner which simply shows the user a loading spinner animation. Perhaps it looks something like this:

import React, { PropTypes } from 'react'

const LoadingSpinner = () => (
  <div className='loading_spinner-wrap'>
    <svg className='loading_spinner' width='60' height='20' viewBox='0 0 60 20' xmlns='http://www.w3.org/2000/svg'>
      <circle cx='7' cy='15' r='4' />
      <circle cx='30' cy='15' r='4' />
      <circle cx='53' cy='15' r='4' />
    </svg>
  </div>
)

export default LoadingSpinner

And maybe I’ve written some basic styles for it to animate the circles:

.loading_spinner-wrap {
  width: 100%;
  padding: 50px 0;
}

.loading_spinner {
  display: block;
  margin: 0 auto;
  fill: #000;

  circle {
    animation-name: upAndDown;
    animation-duration: 2s;
    animation-timing-function: cubic-bezier(.05, .2, .35, 1);
    animation-iteration-count: infinite;

    &:nth-child(2) {
      animation-delay: .18s;
    }

    &:nth-child(3) {
      animation-delay: .36s;
    }
  }
}

@keyframes upAndDown {
  0% { opacity: 0; transform: translateY(0); }
  25% { opacity: 1; transform: translateY(-10px); }
  75% { opacity: 1; transform: translateY(-10px); }
  100% { opacity: 0; transform: translateY(0); }
}

Now, I can set up my DisplayList component to either render the LoadingSpinner component, or my list, depending on whether any items have been passed to it. Like so:

import React, { PropTypes } from 'react'
import LoadingSpinner from './LoadingSpinner'

const DisplayItems = ({ items }) => {
  return items.length ? (
    <div className='items'>
      { items.map((item, index) => <div className='item' key={index} {...item} />) }
    </div>
  ) : <LoadingSpinner />
}

Display.propTypes = {
  items: PropTypes.array
}

export default DisplayItems

Did you see what I did there? I removed the implicit return from the DisplayItems function, and then used a ternary operator to determine which component gets rendered.

If items has any length other than 0, the ternary will evaluate to true and thus render our items list. However, if the length of the array is 0, it will evaluate to false and render our LoadingSpinner component. You might end up with something similar to this:

Loading Stateless Functional Component Gif

You could, of course, use any other component that you would prefer to render instead. You can determine what’s best for your project, and even what’s best per component. But if you’re looking for a way to indicate to your users that you’re expecting data to eventually make it to your stateless functional component, perhaps this pattern will be useful to you.

Let me know if this is helpful to you in the comments and link to any examples you have of this trick or similar ones. I’d love to see them.

Categories:

Related Posts: