Search code examples
javascripthtmlreactjsreact-routerreact-router-dom

<img> tag is not able to render image


I have a few bootstrap cards. On clicking them, I am redirecting to the other page where I am using data passed through NavLink and rendering it.

Here is my code.

Destination.jsx

<div className="row mt-3">
  {firstRowData.map((country, index) => (
    <div className="col-md-3" key={index}>
      <NavLink
        to={`/country/${country.id}`}
        state={{ data: country.id }}
      >
        { Card code }
      </NavLink>
    </div>
  ))}
</div>

CountryInfo.jsx

import React from "react";
import { useLocation} from "react-router-dom";
import countryData from "./data";

function CountryInfo() {
  const location = useLocation();
  let countryId = location.state?.data;

  if (countryData) {
    const image1Url = countryData[countryId].images.image1;
    console.log("Image1 -->", image1Url);
    return (
      <div className="">
        <img
          src={image1Url}
          alt=""
          style={{ height: "100vh", width: "100vw" }}
        />
      </div>
    );

I have a data.jsx file which contains json data.

const data = [
  {
    id: 0,
    name: "Singapore",
    url: "images/card_singapore.jpg",
    price: "$ 300",
    day: 5,
    images: {
      image1: "images/new_0.jpg",
      image2: "images/new_1.jpg",
      image3: "images/new_2.jpg",
      image4: "images/new_3.jpg",
    },
  },
  // some more data.....

Through below code I am able to print correct image address.

console.log("Image1 -->", image1Url);

But img tag is not able to render the image. Why is this happening ?

One Observation :

If I call contryInfo.jsx directly from App.js then I am able to see the image. img tag properly renders image

function App() {
  return (
    <BrowserRouter>
      <CountryInfo />
      <Pages />
    </BrowserRouter>
  );
}

Solution

  • The image source paths are using a relative path since they do not start with a "/" character, e.g. they are source relative to the current URL path. When you render CountryInfo at the root of the app the (assumed) path is just "/" so the relative paths in the PUBLIC directory work, e.g. "/public/images/new_0.jpg", but when CountryInfo is rendered on "/country/:countryId" the images are sourced relative to this path, e.g. /public/country/0/images/new_0.jpg".

    Either update the data to use an absolute path:

    const data = [
      {
        id: 0,
        name: "Singapore",
        url: "/images/card_singapore.jpg",
        price: "$ 300",
        day: 5,
        images: {
          image1: "/images/new_0.jpg",
          image2: "/images/new_1.jpg",
          image3: "/images/new_2.jpg",
          image4: "/images/new_3.jpg",
        },
      },
      ...
    ];
    

    Or prepend this to the image source string when rendering:

    function CountryInfo() {
      const location = useLocation();
      const countryId = location.state?.data;
    
      if (countryData) {
        const image1Url = countryData[countryId].images.image1;
        return (
          <div className="">
            <img
              src={`/${image1Url}`}
              alt="country"
              style={{ height: "100vh", width: "100vw" }}
            />
          </div>
        );
      ...
    
    

    An additional side note: Since the country.id is already used in the URL path when navigating, there's no point really in passing only the same country.id value in route state. Just use the path segment to get the passed country id. Define the route rendering CountryInfo to have a dynamic path segment, e.g. path="/country/:countryId".

    Example:

    function App() {
      return (
        <BrowserRouter>
          <Routes>
            <Route path="/country/:countryId" element={<CountryInfo />} />
            <Route path="/" element={<Pages />} />
          </Routes>
        </BrowserRouter>
      );
    }
    
    <div className="row mt-3">
      {firstRowData.map((country) => (
        <div className="col-md-3" key={country.id}>
          <NavLink to={`/country/${country.id}`}>
            { ...Card code... }
          </NavLink>
        </div>
      ))}
    </div>
    
    import { useParams } from 'react-router-dom';
    
    function CountryInfo() {
      const countryId = useParams();
    
      const { image1, name } = countryData[countryId]?.images ?? {};
    
      if (image1) {
        return (
          <div className="">
            <img
              src={image1}
              alt={name}
              style={{ height: "100vh", width: "100vw" }}
            />
          </div>
        );
      ...