1

I'm learning React and I'm trying to make a simple site which is basically a Giphy search engine by using their API.

So far so good I am fetching and displaying data (the trending Giphy images). The problem is that I don't like how my loading indicator works. It shows for a bit but when it disappears, the (40) images are still being populated in the container.

Is there a way that I can make the loading indicator disappear only when everything is loaded?

<Loader> is my loading indicator. I'm also using some Reactstrap components.

Here are my current 2 components:

App.js

import React, { useState, useEffect } from 'react'
import "react-loader-spinner/dist/loader/css/react-spinner-loader.css"
import Loader from 'react-loader-spinner'
import Results from './Components/Results'
import { UncontrolledAlert } from 'reactstrap'



function App() {
    const [isLoading, setLoading] = useState(true)
    const [gifsData, setGifsData] = useState([])
    const [errorMessage, setErrorMessage] = useState('')

    useEffect(() => {
        const giphyTrending = async () => {
            await fetch(`https://api.giphy.com/v1/gifs/trending?api_key=OGINPHAsY1NNNhf6XIlpX1OygKXDFfXV&limit=50&rating=R`)
                .then(res => res.json())
                .then(data => {
                    setGifsData(data.data)
                    setLoading(false)
                })
                .catch(err => setErrorMessage(err.message))
        }
        giphyTrending()
    }, [])

    if (errorMessage) {
        return (
            <div>
                <UncontrolledAlert color="secondary">{errorMessage}</UncontrolledAlert>
            </div>
        )
    }

    return (
        <div className='App'>
            {isLoading ?
                <Loader className='loader' type="Circles" color="yellow" height={120} width={120} />
                :
                <Results isLoading={isLoading} gifsData={gifsData} />}
        </div>
    )
}

export default App

Results.jsx (not sure this one is needed but just in case)

const Results = (props) => {
    return (
        <div className='gifsContainer'>
            {props.gifsData.map(gif => (
                <div key={gif.id}>
                    <CardImg className='gifs' src={gif.images.fixed_height_small.url} alt={gif.title} />
                </div>))}
        </div>
    )
}

export default Results
bolshed
  • 25
  • 2
  • 7

3 Answers3

0

Looking at this SO question it looks like you can provide an onLoad prop to an img (I'm guessing that's what you're using under the hood of CardImg). If so, you can have each of those fire off a function after they're loaded, keep track of those in your parent component, and when the count of the images you received from your fetch match the count of the images loaded, then you can remove the loading indicator.

This is making a few assumptions. Let me know if you'd like me to sketch out that flow for you.

larz
  • 5,724
  • 2
  • 11
  • 20
  • Sorry for the delay. I was quite busy with other things. Your answer is helpful but I ended up using this solution: https://stackoverflow.com/a/56903585/10950413 which (I think) is similar. Let me know if you find it inappropriate. Thank you! – bolshed Feb 05 '20 at 16:34
0

Check this link you could maintain a count in state and guarentee all images are loaded by hitting 0. So loading = loading.state and imageload.state.count != 0.

https://www.javascriptstuff.com/detect-image-load/

Paul W
  • 21
  • 1
  • Looks interesting but couldn't make it work in functional component with hooks. That ref thing is quite advanced for my level and I couldn't convert it to work in my project. I used this solution - https://stackoverflow.com/a/56903585/10950413. Thank you! – bolshed Feb 05 '20 at 16:35
0

For example, we define a counter:

const [counter, setCounter] = useState(0);

At CardImage component, we use OnLoad function props to update counter when image is loaded completely. And while counter is not equal to gifsData.length - 1 the IndicatorView will be displayed

brianha289
  • 338
  • 1
  • 8