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>
);
}
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>
);
...