Higher Order Component to render spinner React Native

Chirag Shah

By Chirag Shah

on November 15, 2017

In one of our previous blogs, we mentioned how recompose improves both the readability and the maintainability of the code.

We also saw how branch and renderComponent functions from recompose help us in deciding which component to render based on a condition.

We can use the code from renderComponent documentation to render a spinner component when the data is being fetched in a ReactJS application.

Initial Code

1// PatientsList.js
2
3import React, { Component } from 'react';
4import LoadingIndicator from './LoadingIndicator';
5
6export default class PatientsList extends Component {
7
8  state = {
9    isLoading: true,
10    patientsList: [],
11  }
12
13  componentDidMount() {
14    api.getPatientsList().then(responseData => {
15      this.setState({
16        patientsList: responseData,
17        isLoading: false,
18      })
19    })
20  }
21
22  render() {
23    const { isLoading } = this.state;
24    if (isLoading) {
25      return <LoadingIndicator isLoading={isLoading} />
26    } else {
27      return (
28        <ScrollView>
29          // Some header component
30          // View rendering the patients
31        </ScrollView>
32      )
33    }
34  }

In the above code, when the PatientsList component mounts, it fetches the list of patients from the API. During this time, the isLoading state is true, so we render the LoadingIndicator component.

Once the API call returns with the response, we set the isLoading state to false. This renders ScrollView component, with our list of patients.

The above code works fine, but if our app has multiple screens, which show the loading indicator and fetch data, the above way of handling it becomes repetitive and hard to maintain.

Building a higher order component

Here's where Higher Order Components(HOC) are very useful. We can extract the logic for the ability to show the loading indicator in a HOC.

1// withSpinner.js
2
3import React from "react";
4import { ScrollView } from "react-native";
5import LoadingIndicator from "./LoadingIndicator";
6
7const withSpinner = (Comp) => ({ isLoading, children, ...props }) => {
8  if (isLoading) {
9    return <LoadingIndicator isLoading={isLoading} />;
10  } else {
11    return <Comp {...props}>{children}</Comp>;
12  }
13};
14
15export default withSpinner;

Here, we created a HOC component which accepts a component and the isLoading prop.

If isLoading is true, we show the LoadingIndicator. If isLoading is false, we show the supplied component with its children, and pass in the props.

Now, we can use the above HOC in our PatientsList.js file. The supplied component can be any React Native component based on the use case. Here in our case, its a ScrollView.

1// PatientsList.js
2
3import { ScrollView } from 'react-native';
4import withSpinner from './withSpinner';
5const ScrollViewWithSpinner = withSpinner(ScrollView);
6
7export default class PatientsList extends Component {
8
9  state = {
10    isLoading: true,
11    patientsList: [],
12  }
13
14  componentDidMount() {
15    api.getPatientsList().then(responseData => {
16      this.setState({
17        patientsList: responseData,
18        isLoading: false,
19      })
20    })
21  }
22
23  render() {
24    const { isLoading } = this.state;
25    return(
26      <ScrollViewWithSpinner
27        isLoading={isLoading}
28        // other props
29      >
30        // Some header component
31        // View rendering the patients
32      </ScrollViewWithSpinner>
33    )
34  }

Conclusion

Because of the above extraction of logic to a HOC, we can now use the same HOC in all our components which render a loading indicator while the data is being fetched.

The logic to show a loading indicator now resides in a HOC. This makes the code easier to maintain and less repetitive.

Stay up to date with our blogs. Sign up for our newsletter.

We write about Ruby on Rails, ReactJS, React Native, remote work,open source, engineering & design.