skip to Main Content

I’m trying to show a loading spinner (or really any HTML element for that matter) while my image is loading, the thing is I am using this ImageComponent to display an image in a random movie generator, I was able to get the spinner working just with the first image, but after that when I get a new movie the image of the previous movie stays until the new image is loaded.

Here’s the code of the image component:

import Image from "next/image";
import { useState } from "react";

export default function ImageComponent(image: PrimaryImage) {
  const [loading, setLoading] = useState(true)

  function onImageLoad() {
    setLoading(false)
    console.log("loaded")
  }

  return (
    <div className="relative h-full m-auto">
      <div style={{ display: loading ? "block" : "none" }}>
        Loading Spinner goes here
      </div>
      <Image className="object-contain"
        src={image.url}
        alt="Image"
        fill
        onLoad={onImageLoad}
        priority
        style={{ display: loading ? "none" : "block" }}
      />
    </div>
  )
}

And here is the code of the full page:

"use client"
import { useEffect, useRef, useState } from "react";
import { getMoviesRequest } from "./requests";
import MovieImageComponent from "./components/MovieImage";

export default function Page() {
  const moviesCache = useRef<Movie[]>([])
  const index = useRef(0)
  const [movie, setMovie] = useState<Movie>({
    titleText: { text: "" },
    primaryImage: { width: 0, height: 0, url: "/default_image.png" },
    releaseDate: { day: 0, month: 0, year: 0 }
  })

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

  function refreshMoviesCache() {
    // do some stuff to refresh the movies cache
  }
  function setNewMovie() {
    // do some stuff to set a new movie
  }

  return (
    <div>
      <h3>
        Movie Generator
      </h3>
      {MovieImageComponent(movie.primaryImage)}
      <div className="text-center p-3">
        <h1>{movie.titleText.text}</h1>
        <h2>{movie.releaseDate.year}</h2>
        <button onClick={setNewMovie}>
          Otra Pelicula
        </button>
      </div>
    </div>
  )
}

Any help would be very much appreciated.

2

Answers


  1. use an if statement instead, like this:

    <div className="relative h-full m-auto">
        {loading ?
           <div>
             Loading Spinner goes here
           </div>
         :
           <Image className="object-contain"
             src={image.url}
             alt="Image"
             fill
             onLoad={onImageLoad}
             priority
           />
        }
    </div>
    

    and you need to change the loading state every time that you send a request for new movie.

    Login or Signup to reply.
  2. you could have a state for default image

    const [imageUrl,setImageUrl]=useState(yourDefaultImageUrl)
    

    when image loads you have onImageLoad, and you set the final url here:

    function onImageLoad() {
        setLoading(false)
        setImageUrl(image.url)
        console.log("loaded")
      }
    

    as src use imageUrl

       <Image className="object-contain"
            src={imageUrl}
            alt="Image"
            fill
            onLoad={onImageLoad}
            priority
            style={{ display: loading ? "none" : "block" }}
          />
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search