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