React Suspense not working as expected when fetching data

1.5k Views Asked by At

I have a react component in which I am fetching data from the pokeapi. I am trying to render it with Suspense using browser's fetch but I am not able to figure out where I am going wrong.

function FirstPageIndex() {
  const [pokemon, setPokemon] = useState({ abilities: [] });
  const [loading, setLoading] = useState(false);

  console.log("This has been rendered only once");

  function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  const getDataFunction = async (e) => {
    try {
      e.preventDefault();
      setLoading(true);
      const r = await fetch("https://pokeapi.co/api/v2/pokemon/ditto");
      const res = await r.json();

      await sleep(4000);

      console.log("This is the data");
      console.log(res);
      setPokemon(res);
      setLoading(false);
    } catch (e) {}
  };

  return (
    <div>
      This is coming from the home page
      <button onClick={getDataFunction}>Get Data</button>
      <Suspense fallback={<h2>Suspense in loading...</h2>}>
        {pokemon.abilities.map((ability, i) => (
          <p key={i}>
            This is my ability {i + 1}: {ability.ability.name}
          </p>
        ))}
      </Suspense>
    </div>
  );
}

I have imported {Suspense} from "react" in this component.

The expected behaviour is when I click on get data, it waits for 3 seconds and then it renders the data, during which time it should show the Suspense's fallback which it is not showing.

EDIT: Updated code to incorporate promise based delay

Please have a look at it?

1

There are 1 best solutions below

1
On

setTimeout is not a promise so await won't work here. try doing this

  function FirstPageIndex() {
  const [pokemon, setPokemon] = useState({ abilities: [] });
  const [loading, setLoading] = useState(false);

  useEffect(() => {}, []);

  console.log("This has been rendered only once");

  const getDataFunction = async (e) => {
    try {
      e.preventDefault();
      setLoading(true);
      const r = await fetch("https://pokeapi.co/api/v2/pokemon/ditto");
      const res = await r.json();

      setTimeout(() => {
        console.log("This is the data");
        console.log(res);
        setPokemon(res);
        setLoading(false);
      }, 3000);

      
    } catch (e) {}
  };

  if (loading) return <p>This is loading state</p>;
  return (
    <div>
      This is coming from the home page
      <button onClick={getDataFunction}>Get Data</button>
      <Suspense fallback={<h2>Suspense in loading...</h2>}>
        {/* <PokeData resource={pokemon} ></PokeData> */}
        {pokemon.abilities.map((ability, i) => (
          <p key={i}>
            This is my ability {i + 1}: {ability.ability.name}
          </p>
        ))}
      </Suspense>
    </div>
  );
}