somniumm
somniumm

Reputation: 115

React loading state doesn't show

I'm fetching data from an API based on user input. I'd like to display the text "Loading.." while the data is being fetch.

My problem is that this "Loading.." is never displayed no matter how slow my internet is. Although I set isLoading to be true before fetching data.

Additionally, I'm logging console.log("isLoading:", isLoading) in the body. Why does it get refreshed every i input something BEFORE hitting submit button.

import { useState } from "react";

// example user:  0x147412d494731cbb91dbb5d7019464a536de04dc

function App() {
  const [data, setData] = useState([]);
  const [enteredWallet, setEnteredWallet] = useState("");
  const [isLoading, setIsLoading] = useState(false);

  const walletChangeHandler = (event) => {
    setEnteredWallet(event.target.value);
  };

  const submittedHandler = (event) => {
    event.preventDefault();
    fetchNFTHandler(enteredWallet);
    console.log("enteredWallet:", enteredWallet);
  };

  function fetchNFTHandler(owner) {
    setIsLoading(true);
    fetch(
      `https://api.opensea.io/api/v1/assets?owner=${owner}&order_direction=desc&offset=0&limit=10`
    )
      .then((res) => {
        return res.json();
      })
      .then((data) => {
        const tranformedData = data.assets.map((element, index) => {
          return {
            title: element.name,
            id: index,
          };
        });
        setData(tranformedData);
      });
    setIsLoading(false);
  }

  return (
    <div className="App">
      <header className="App-header">
        <h3>Show me assets in this wallet</h3>
        <form onSubmit={submittedHandler}>
          <input
            placeholder="wallet address"
            value={enteredWallet}
            onChange={walletChangeHandler}
          />
          <button>Submit</button>
        </form>
        <div>
          {console.log("isLoading:", isLoading)}
          {!isLoading &&
            data.map((element) => <li key={element.id}>{element.title}</li>)}
          {isLoading && <p>Loading..</p>}
        </div>
      </header>
    </div>
  );
}

export default App;

Upvotes: 0

Views: 960

Answers (2)

Niklas
Niklas

Reputation: 49

The setIsLoading(false); is outside of the then(...) part. This should do the trick:

  function fetchNFTHandler(owner) {
    setIsLoading(true);
    fetch(
      `https://api.opensea.io/api/v1/assets?owner=${owner}&order_direction=desc&offset=0&limit=10`
    )
      .then((res) => {
        return res.json();
      })
      .then((data) => {
        const tranformedData = data.assets.map((element, index) => {
          return {
            title: element.name,
            id: index,
          };
        });
        setData(tranformedData);
      })
      .finally(() => {
        setIsLoading(false);
      });
  }

Make sure to place it into a finally(...) as otherwise the loading state won't be turned off when an error occures.

Upvotes: 1

hellogoodnight
hellogoodnight

Reputation: 2129

Because you call setLoading(false) before your promise is resolved.

Do this instead:

function fetchNFTHandler(owner) {
    setIsLoading(true);
    fetch(
      `https://api.opensea.io/api/v1/assets?owner=${owner}&order_direction=desc&offset=0&limit=10`
    )
      .then((res) => {
        return res.json();
      })
      .then((data) => {
        const tranformedData = data.assets.map((element, index) => {
          return {
            title: element.name,
            id: index,
          };
        });
        setData(tranformedData);
        setIsLoading(false); // Move it here
      });
  }

Don't put your console.log-statement in the jsx btw, put it above the return statement.

Upvotes: 2

Related Questions