Leviathan
Leviathan

Reputation: 656

React display loading animation for api call duration

Currently I feel like the more I read about React, the less I understand.

I am trying to solve this simple problem: During the data-fetching for my component, show a loading spinner.

This is how I thought it would work:

  1. use State to monitor loading
    const [isLoading, setIsLoading] = useState(false);

  2. use conditional rendering on this state
    return ({isLoading && <div>I am loading</div>});

  3. setLoading when api call is started and reset it when a reponse arrived

    useEffect(() => {
     const fetchData = async () => {
       let result;
       setIsLoading(true);    
       result = await api.get(URL);    // this takes 2000ms!
       setData(result.data);
       setIsLoading(false);
     };
    
     fetchData();
    },[api]);
    

But, as the documentation says, setState is async and can be sent in batches. the network call takes 2 seconds, but I never see a loading animation.
So how do I do this?

Edit: This is how you can do this. My error was somewhere else - the setIsLoading(false) was also in a different useEffect, which had the data as dependency. I had to wrap the entire logic inside that useEffect with if(data), since on the first render, my data was undefined, but this still triggered the initial useEffect, probably like the old componentDidMount logic I guess - and the loading anim stopped way too soon.

Upvotes: 0

Views: 3612

Answers (1)

TKoL
TKoL

Reputation: 13912

I think what you've got there works. I've implemented it here: codesandbox

import "./styles.css";
import React, { useState, useEffect } from "react";

export default function App() {
  const [isLoading, setIsLoading] = useState(false);
  useEffect(() => {
    const fetchData = async () => {
      let result;
      setIsLoading(true);
      result = await api.get(URL); // this takes 2000ms!
      //setData(result.data);
      setIsLoading(false);
    };

    fetchData();
  }, []);
  return (
    <div className="App">
      {isLoading ? <p>currently loading</p> : null}
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

const api = {
  get: async function () {
    await new Promise((r, e) => setTimeout(r, 2000));
  }
};

Upvotes: 3

Related Questions