Home > Blockchain >  Next/image doesn't load my src image when I use a map
Next/image doesn't load my src image when I use a map

Time:03-27

I use next/image to load my images in my app. It works fine except for a carousel with multiple images. When I do like this I have that error :

Error: Image is missing required "src" property. Make sure you pass "src" in props to the next/image component. Received: {}

The problem is not because I have an entity without any file

image.js

import { getStrapiMedia } from "../utils/medias"
import NextImage from "next/image"

const Image = (props) => {
  if (!props.media) {
    return <NextImage {...props} />
  }

  const { url, alternativeText } = props.media

  const loader = ({ src }) => {
    return getStrapiMedia(src)
  }

  return (
    <NextImage
      loader={loader}
      layout="responsive"
      objectFit="contain"
      width={props.media.width}
      height={props.media.height}
      src={url}
      alt={alternativeText || ""}
    />
  )
}

export default Image

Carousel.js

import React, { useCallback } from "react"
import useEmblaCarousel from "embla-carousel-react"
import NextImage from "./Image"

export const EmblaCarousel = (product) => {
  const [emblaRef, emblaApi] = useEmblaCarousel()

  useEmblaCarousel.globalOptions = { loop: true }

  const scrollPrev = useCallback(() => {
    if (emblaApi) emblaApi.scrollPrev()
  }, [emblaApi])

  const scrollNext = useCallback(() => {
    if (emblaApi) emblaApi.scrollNext()
  }, [emblaApi])

  return (
    <div className="embla" ref={emblaRef}>
      <div className="embla__container">
        {product.gallery.map((_gallery) => (
          <div key={_gallery.id}>
            <NextImage media={_gallery.image} className="embla__slide" />
          </div>
        ))}
      </div>
      <button
        className="hidden md:inline embla__prev mr-2"
        onClick={scrollPrev}
      >
        Prev
      </button>
      <button
        className="hidden md:inline embla__next ml-2"
        onClick={scrollNext}
      >
        Next
      </button>
    </div>
  )
}

export default EmblaCarousel

CodePudding user response:

The issue is

 if (!props.media) {
    return <NextImage {...props} />
  }

in your custom Image component. When the media prop is falsy like undefined or null, you're passing everything else to NextImage but that everything else doesn’t include src prop which is mandatory for next Image component. Also your url extraction is dependent on media prop to be truthy and have a property called url. Can be seen from the next line :-

const { url, alternativeText } = props.media

And you intend to pass this url to src as can be seen from your usage. Either you can return null when media is falsy or you can filter out those items in your list where media prop is falsy and then map on it.

CodePudding user response:

Replace NextImage with Image

import { getStrapiMedia } from "../utils/medias"
import Image from "next/image"

const NextImage = (props) => {
  if (!props.media) {
    return <Image {...props} />
  }

  const { url, alternativeText } = props.media

  const loader = ({ src }) => {
    return getStrapiMedia(src)
  }

  return (
    <Image
      loader={loader}
      layout="responsive"
      objectFit="contain"
      width={props.media.width}
      height={props.media.height}
      src={url}
      alt={alternativeText || ""}
    />
  )
}

export default NextImage

Carousel.js

import React, { useCallback } from "react"
import useEmblaCarousel from "embla-carousel-react"
import NextImage from "./Image"

export const EmblaCarousel = (product) => {
  const [emblaRef, emblaApi] = useEmblaCarousel()

  useEmblaCarousel.globalOptions = { loop: true }

  const scrollPrev = useCallback(() => {
    if (emblaApi) emblaApi.scrollPrev()
  }, [emblaApi])

  const scrollNext = useCallback(() => {
    if (emblaApi) emblaApi.scrollNext()
  }, [emblaApi])

  return (
    <div className="embla" ref={emblaRef}>
      <div className="embla__container">
        {product.gallery.map((_gallery) => (
          <div key={_gallery.id}>
            <NextImage media={_gallery.image} className="embla__slide" />
          </div>
        ))}
      </div>
      <button
        className="hidden md:inline embla__prev mr-2"
        onClick={scrollPrev}
      >
        Prev
      </button>
      <button
        className="hidden md:inline embla__next ml-2"
        onClick={scrollNext}
      >
        Next
      </button>
    </div>
  )
}

export default EmblaCarousel
  • Related