Categories
React Tips

React Tips — Loading Data

Spread the love

React is the most used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps.

In this article, we’ll look at how to load data in our React components.

Loading Data When the Component First Loads with the useEffect Hook

If we’re using hooks in React function components, we can load data from an API when the component first loads by using the useEffect hook with an empty array as the second argument.

For instance, we can load data by writing:

import React, { useEffect, useState } from "react";

export default function App() {
  const [data, setData] = useState({});
  const loadData = async () => {
    const res = await fetch("https://api.agify.io/?name=michael");
    setData(await res.json());
  };

  useEffect(() => {
    loadData();
    return () => {};
  }, []);
  return <p>{data.name}</p>;
}

In the code above, we use the useEffect hook to fetch data from an API and then set the result to the data state variable with the setData function.

Then we call the loadData function in the useEffect callback. The 2nd argument of the useEffect hook is an empty array.

React then will rerender the data as the data from the API is fetched. The useEffect callback will only run when the component first loads if the 2nd argument of useEffect is an empty array.

Loading Data When the Component’s Prop Changes

If we pass in the prop variable to the array in the 2nd argument of useEffect , the callback that we pass into the 1st argument will run as the prop changes.

For instance, we can write the following code fetch data from an API as our prop changes:

import React, { useEffect, useState } from "react";

const Name = ({ name }) => {
  const [data, setData] = useState({});
  const loadData = async () => {
    const res = await fetch(`https://api.agify.io/?name=${name}`);
    setData(await res.json());
  };

  useEffect(() => {
    loadData();
    return () => {};
  }, [name]);
  return <p>{data.name}</p>;
};

export default function App() {
  const [name, setName] = useState("");
  return (
    <div>
      <input onChange={e => setName(e.target.value)} />
      <Name name={name} />
    </div>
  );
}

In the code above, we have an input in App , where the inputted value is set as the value of the name variable with setName . Then we have the Name component, which passes the name prop with the value name ,

In Name , we have the useEffect hook which is similar to what we have before. The name prop is passed into the array in the second argument of useEffect , which means that it’s watched.

Note that we returned a function in the useEffect callback. This is used for clean up code. Whenever we have something in the array in the 2nd argument of useEffect , we have to return a cleanup function. Otherwise, we’ll get a ‘destroy is not a function’ error.

Then when we type in something, we’ll see that data is fetched from the API and the data is displayed as the output.

Adding a Loading Indicator in Fetch Calls

We can use the react-promise-tracker package to watch for loading promises and sets a state to indicate that one or more promises are loading.

To use it, we first install it by running:

npm i react-promise-tracker

Then we can use it as follows:

import React, { useEffect, useState } from "react";
import { usePromiseTracker, trackPromise } from "react-promise-tracker";

const sleep = ms => new Promise(r => setTimeout(r, ms));

export default function App() {
  const [data, setData] = useState({});
  const { promiseInProgress } = usePromiseTracker();
  const loadData = async () => {
    await sleep(2000);
    const res = await fetch("https://api.agify.io/?name=michael");
    setData(await res.json());
  };
  useEffect(() => {
    trackPromise(loadData());
    return () => {};
  }, []);

  return <p>{promiseInProgress ? "loading" : data.name}</p>;
}

In the code above, we have 2 promises. One if the sleep function call, which returns a promise. Then we have our fetch request promises in the loadData function.

We then use the trackPromise function from react-promise-tracker to track whether the promises are finished or not.

If one or more promises are loading, then we have the promiseInProgress state is set to true . When it’s true , we show the ‘loading’ text. When the promises are done, we show the value of data.name .

This is a great package that makes tracking the loading of promises easy. We can also add a delay as follows to delay the loading of the promise as follows:

import React, { useEffect, useState } from "react";
import { usePromiseTracker, trackPromise } from "react-promise-tracker";

const sleep = ms => new Promise(r => setTimeout(r, ms));

export default function App() {
  const [data, setData] = useState({});
  const { promiseInProgress } = usePromiseTracker({ delay: 500 });
  const loadData = async () => {
    await sleep(2000);
    const res = await fetch("https://api.agify.io/?name=michael");
    setData(await res.json());
  };
  useEffect(() => {
    trackPromise(loadData());
    return () => {};
  }, []);

  return <p>{promiseInProgress ? "loading" : data.name}</p>;
}

In the code above, we have:

usePromiseTracker({ delay: 500 })

to prevent flickering when the component is loaded on high-speed connections.

Conclusion

In React function components, it isn’t immediately obvious where we place our code to load data. The correct way is to add callbacks to the useEffect hook.

The 2nd argument of useEffect will indicate when the callback will run. If it’s empty, then it’s run when the component first loads. If it’s not, then it’ll watch the value changes of the items in the array and runs the callback when any of them change.

We have to return a cleanup function to run clean up code if needed. Even if we don’t, we still need to return an empty function.

To add a loading indicator when promises load, we can use the react-promise-tracker package to track that and render the loading indicator according to the state returned by this package.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *