Show a Spinner While a Component is Loading using Recompose

Tim Kindberg
InstructorTim Kindberg

Share this video with your friends

Send Tweet
Published 5 years ago
Updated 3 years ago

Learn how to use the 'branch' and 'renderComponent' higher-order components to show a spinner while a component loads.

[00:00] I have a withUserData higher-order component here. It fetches some user data, and it passes the data to any wrapped component. I'm using it here around my user component. It receives the user data in the form of name and status, and it's checking if name or status are undefined.

[00:19] It wants to show a spinner, otherwise show the user. If I refresh, I can see a spinner shows up for a couple seconds until the data is received. I would like to separate out the concern of the spinner. I'm going to store that into its own component.

[00:43] I'm also going to remove this logic here. Now, I'll declare a new higher-order component called withSpinnerWhileLoading. We'll make use of the branch higher-order component from Recompose. Branch is similar to an if-then statement.

[00:59] The first parameter is a predicate. If the predicate is true, it will render the second parameter. If it's false, it will render the third parameter. Our predicate is the WhileLoading part. We want to check if it's loading.

[01:20] If it is loading, I want to render a component, and I want to render the spinner component. The third parameter is actually optional. If you don't supply it, it will fall back to rendering the wrapped component. I often find that I don't supply a third parameter.

[01:35] Now, I have to define our isLoading predicate. The predicate in the branch higher-order component always takes in the component's props. Instead of checking for name or status, I'd like to be a little bit more deliberate.

[01:53] Let's go ahead and add a loading prop, and I'll just check for that. We'll return it. It'll either be true or false. Now, I need to add that.

[02:07] I'll add a getInitialState hook, and I'll make sure to return loading set to true initially. When I get my data, I want to set loading to false. Now, I want to compose both the withUserData and withSpinnerWhileLoading higher-order components into a single higher-order component.

[02:40] We'll use that one instead. I should be able to refresh and still see the same, exact behavior as before.

Nikolaj
Nikolaj
~ 5 years ago

Great course! Really appreciate it.

But that this example is somehow not working. It seems like the initial state is not passed into the component. I first thought I made something wrong in my development, but then I ran the code provided in Plunker, and that does not show the Spinner either...

When I replace the getInitialState method with the property state: { loading: true } it works for me.

Tim Kindberg
Tim Kindberginstructor
~ 5 years ago

Thanks you Nikolai! Looks like Recompose just released an update that replaced createClass usage with class extends Component usage behind the scenes. So I'll have to update the example.

Tim Kindberg
Tim Kindberginstructor
~ 5 years ago

Example has been updated to show state property usage instead of getInitialState method usage.

Nathan
Nathan
~ 5 years ago

Is there a good way to externalize the withSpinnerWhileLoading outside of a component? I am not sure I am asking that correctly.

I was hoping to do something like the following but I cant seem to figure it out.

const enhance =
  compose(
    connect(
      (state, props) => {
        return {
          name: state.user.name
        }
      },
      {saveLease, saveTenant}
    ),
    withSpinnerWhileLoading({
      isLoading: (props) => {
        return !props.name
      }
    }),
  )

where withSpinnerWhileLoading looks like

export const withSpinnerWhileLoading = ({isLoading}) => branch(
    isLoading,
    renderComponent(Spinner)
)