Search code examples
imagenext.jsstrapi

Next.js Image Component Error: "Image is missing required 'src' property"


Strapi v4.11.5 and Next.js 13.4.19

I'm encountering an issue while trying to fetch images in a Next.js project. I have a component that uses the Image component from Next.js to display images fetched from an API. However, I'm consistently receiving "Image is missing required 'src' property" when attempting to load the images.

"use client"

import React from 'react';
import useFetch from '@hooks/usefetch';
import Link from 'next/link';
import Image from 'next/image';
import '@styles/globals.css';
import TopBanner from '@components/TopBanner';
import Nav from '@components/Nav';
import Search from '@components/Search';
import Footer from '@components/Footer';
import { FaRegBookmark, FaMapMarkerAlt } from 'react-icons/fa';
import qs from 'qs';

const vendors = () => {

const queryParams = {
  fields: [
    'Name',
    'About',
    'Images.url',
    'Review.Rating',
    'Services.Name',
    'Location.Street',
    'Location.City',
    'Logo.url',
  ],
  populate: {
    Images: {
      fields: ['url'],
    },
    Review: {
      fields: ['Rating'],
    },
    Services: {
      fields: ['Name'],
    },
    Location: {
      fields: ['Street', 'City'],
    },
    Logo: {
      fields: ['url'],
    },
  },
};

const queryString = qs.stringify(queryParams, { indices: false });

const apiUrl = `http://localhost:1044/api/vendors?${queryString}`;

const { loading, error, data } = useFetch(apiUrl);

  if (loading) return <div className='loading-center'><div className='building-blocks'><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div></div>;
  if (error) return <p>Error :(</p>;

  return (
    <div>
      <TopBanner />
      <Nav />
      <div className="w-full flex-center flex-col max-w-screen-lg">
      <Search />
        {data.data.map((vendor) => (
          <div key={vendor.id} className="vendor-card bg-[#f4f4f4] rounded-lg p-10 m-20 mt-10 mb-4 w-1/2">
            <div className="flex">
              <div className="w-1/6">
                <Image
                  src={vendor.attributes.Logo.url}
                  alt="Vendor Logo"
                  width={70}
                  height={70}
                  className="object-contain rounded-lg"
                />

              </div>
              <div className="w-3/4">
                <h2>{vendor.attributes.Name}</h2>
                <small className="flex items-center">
                <FaRegBookmark className="mr-2" /><strong>{vendor.attributes.Review.Rating} Saves</strong></small>
                <small className="flex items-center">
                  <FaMapMarkerAlt className="mr-2" />
                  <a
                    href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(vendor.attributes.Location.Street + ', ' + vendor.attributes.Location.City)}`}
                    target="_blank"
                    rel="noopener noreferrer"
                  >
                    {vendor.attributes.Location.Street}, {vendor.attributes.Location.City}
                  </a>
                </small>
                <div className="mt-2">
                <small>
                <p><strong>Services</strong></p>{' '}
                  {vendor.attributes.Services.map((service, index) => (
                    <span key={service.id}>
                      {service.Name}
                      {index !== vendor.attributes.Services.length - 1 ? ' • ' : ''}
                    </span>
                  ))}
                </small>
                </div>
              </div>
              <div className="w-1/6 flex justify-end">
                <Link href={`/vendor/${vendor.id}`}>
                  <button className="purple_btn">View</button>
                </Link>
              </div>
            </div>
          </div>
        ))}
      </div>
      <Footer />
    </div>
  );
};

export default vendors;

Here's what I've done so far:

I've verified the constructed image URLs, and they seem correct, including the full path to the images on the server. The API response contains the expected image URLs, and the data structure seems correct. I've checked the server logs, but I couldn't find any specific error messages related to this issue. I've followed the guidance from the Next.js documentation and added the required configuration in next.config.js to include the hostname "localhost" in the images property.

Despite these steps, I'm still encountering the error. Could there be any other factors causing this "Image is missing required 'src' property" when trying to load images in my Next.js project? Any insights or suggestions would be greatly appreciated.

UPDATE: I have tried various approaches since posting this question. I thought the issue might be related to the way the image URL is being constructed or handled by the Image component. After analysing the code and responses, I implemented a slightly modified approach to ensure that the logo URL is accessed correctly. Here's the relevant part of the code:

      <div className="w-1/6">
    {console.log('Logo URL:', 'http://localhost:1044' + vendor.attributes.Logo.data.url)}
    {vendor.attributes.Logo && vendor.attributes.Logo.data && vendor.attributes.Logo.data.url ? (
      <Image
        src={'http://localhost:1044' + vendor.attributes.Logo.data.url}
        alt="Vendor Logo"
        width={70}
        height={70}
        className="object-contain rounded-lg"
      />
    ) : (
      <Image
        src="/images/logo-placeholder.png"
        alt="Placeholder Logo"
        width={70}
        height={70}
        className="object-contain"
      />
    )}
  </div>```

After implementing this approach, the error was fixed. However, even though the error was resolved, the image still didn't appear. The logged output was: Logo URL: http://localhost:1044/undefined.

I'm still investigating the issue and seeking further guidance to ensure that the logo image is correctly displayed. Thanks for your help in advance.


Solution

  • The error from Next.js means that src attribute supplied to the <Image /> is undefined.

    Given that your component is:

    <Image
      src={vendor.attributes.Logo.url}
      alt="Vendor Logo"
      width={70}
      height={70}
      className="object-contain rounded-lg"
    />
    

    Since you are supplying vendor.attributes.Logo.url as the src, that means vendor.attributes.Logo.url is undefined.

    Update 1:

    In your latest code, I can see that the <Image /> component has been updated.

    <Image
      src={'http://localhost:1044' + vendor.attributes.Logo.data.url}
      alt="Vendor Logo"
      width={70}
      height={70}
      className="object-contain rounded-lg"
    />
    

    But vendor.attributes.Logo.data.url is also undefined. It's supposed to be vendor.attributes.Logo.data.attributes.url instead.