Search code examples
reactjspromisefetch-api

Suspense React not working on fetching data


I'am trying to use Suspense to render a fallback while the Promise is not solved. What am I doing wrong?

It's supposed to render the fallback while the fetch promise don't return the data. But when i try to fetch the data from the browser the fallback does not appear.

export const MainFlow = () => {
    const URL_BASE = 'https://api.thedogapi.com/v1/images/search'
    const [data, setData] = useState<any[]>([])

    const fetchData = async () => {
        const response = await httpService.request({
            url: `${URL_BASE}?limit=10`,
            method: 'get',
            headers: { 'x-api-key': 'some-key' }
        })
        setData(response.body)
    }

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

    const DogImage: FC<DogImageProps> = ({ url }) => {
        return (
            <img src={url} alt="I'am a doggo." className="mfone__dog-images" />
        )
    }

    return (
        <div id="mfone__dog-container">
            <Suspense fallback={<div>Loading...</div>}>
                <div id="mfone__images-box">
                    {data
                        ? data.map((element, index) => {
                                return (
                                    <DogImage key={index} url={element.url} />
                                )
                          })
                        : null}
                </div>
            </Suspense>
            <div id="mfone__links-box">
                <Link to="/" className="mfone__dog-links">
                    Back to Home page
                </Link>
                <button
                    onClick={() => fetchData()}
                    className="mfone__dog-links"
                >
                    More Doggos
                </button>
            </div>
        </div>
    )
}

I have tried to put the Suspense tag inside the div that has the id "mfone__images-box", but still not working:

return (
        <div id="mfone__dog-container">
            <div id="mfone__images-box">
                <Suspense fallback={<div>Carregando...</div>}>
                    {data
                        ? data.map((element, index) => {
                                return (
                                    <DogImage key={index} url={element.url} />
                                )
                          })
                        : null}
                </Suspense>
            </div>
            <div id="mfone__links-box">
                <Link to="/" className="mfone__dog-links">
                    Back to Home page
                </Link>
                <button
                    onClick={() => fetchData()}
                    className="mfone__dog-links"
                >
                    More Doggos
                </button>
            </div>
        </div>
    )

Solution

  • As of now, Suspense only works when implementing lazy loading of a component, it doesn't support your use case which is data fetching. In this case, you could create a loading state which is set to true as soon as the data fetching function starts executing and then, set to false once it completes, that way you can display the loading/fetching UI based on that state.

    Update: Suspense can now be used for data fetching purposes when implementing React Server Components, which have moved from experimental into full support. Next.js v13 has started implementing React Server Components in its still experimental app directory feature.