2

I am use Redux toolkit for show data of a API and I need show for the user a "loading data..." or a spinner before of show the city information.

I am trying use the React Suspense, but don't work. Probably I am doing things wrong.

informationCIty.js (Code with Suspense)

import React, { useEffect, Suspense } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getInformationCity } from "../informationCity/informationCitySlice";

export const InformationCity = () => {
  const dispatch = useDispatch();
  const selectedCity = useSelector((state) => state?.cities?.selectedCity);
  const informacoes = useSelector(
    (state) => state?.informationCity?.dataInformation
  );

  useEffect(() => {
    dispatch(getInformationCity(selectedCity));
  }, [dispatch, selectedCity]);

  return (
    <div>
      <Suspense fallback="Loading information of city">
        {informacoes.map((item, i) => (
          <li key={i}>
            City ID: {item.id}
            <br />
            City Name: {item.nome}
            <br />
          </li>
        ))}
      </Suspense>
    </div>
  );
};

Code full in codesandbox

Someone help me please?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Begginer
  • 65
  • 1
  • 7

3 Answers3

3

Suspense for data fetching on the client is still not officially supported in React 18. From the release notes:

Ad hoc data fetching with Suspense is technically possible, but still not recommended as a general strategy.

Until React has an official story for this, Redux will also not have one. The risk that React changes their approach (which they have done multiple times in the past) is just too high.

phry
  • 35,762
  • 5
  • 67
  • 81
2

According to the posted sandbox, it seems that loading status has already been managed by createAsyncThunk, and the same pattern is used across the app.

Perhaps unless Suspense is mandatory, this component could easily implement loading status by reading it from the state: (forked example with the following changes: codesandbox)

const loading = useSelector((state) => state?.informationCity?.loading);

  return (
    <div>
      {informacoes && informacoes.length > 0 && loading && (
        <h2>"Loading information of city"</h2>
      )}
      {informacoes &&
        informacoes.length > 0 &&
        !loading &&
        informacoes.map((item, i) => (
          <li key={i}>
            City ID: {item.id}
            <br />
            City Name: {item.nome}
            <br />
          </li>
        ))}
    </div>
  );
John Li
  • 6,976
  • 3
  • 3
  • 27
1

I know this isn't ideal but I have a whole project like this with redux and loading, trying to create skeletons with Suspense, but it hasn't work no matter what I tried. What I do on my site, is have a top level loading state and if that state is > 0 then return

return (
<Layout>
     {loading ? (
         <Loading /> 
      ) : (
         <Component />
      )} 
</Layout>

Ideally, if you want, you could put this loading state inside the layout.

Additionally if you want to load skeletons u would pass the loading into the component and create a skeleton component inside and do the same thing.

Abhishek Vyas
  • 599
  • 1
  • 9
  • 24