I'm writing a simple application that displays by mapping matching data from a data.js file.
This is what the data.js file looks like:
export const data = {
destinations: [
{
name: "Moon",
images: {
png: require("../assets/destination/image-moon.png"),
webp: "../assets/destination/image-moon.webp",
},
description:
"See our planet as you’ve never seen it before. A perfect relaxing trip away to help regain perspective and come back refreshed. While you’re there, take in some history by visiting the Luna 2 and Apollo 11 landing sites.",
distance: "384,400 km",
travel: "3 days",
},
{
name: "Mars",
images: {
png: require("../assets/destination/image-mars.png"),
webp: "../assets/destination/image-mars.webp",
},
description:
"Don’t forget to pack your hiking boots. You’ll need them to tackle Olympus Mons, the tallest planetary mountain in our solar system. It’s two and a half times the size of Everest!",
distance: "225 mil. km",
travel: "9 months",
},
{
name: "Europa",
images: {
png: require("../assets/destination/image-europa.png"),
webp: "../assets/destination/image-europa.webp",
},
description:
"The smallest of the four Galilean moons orbiting Jupiter, Europa is a winter lover’s dream. With an icy surface, it’s perfect for a bit of ice skating, curling, hockey, or simple relaxation in your snug wintery cabin.",
distance: "628 mil. km",
travel: "3 years",
},
{
name: "Titan",
images: {
png: require("../assets/destination/image-titan.png"),
webp: "../assets/destination/image-titan.webp",
},
description:
"The only moon known to have a dense atmosphere other than Earth, Titan is a home away from home (just a few hundred degrees colder!). As a bonus, you get striking views of the Rings of Saturn.",
distance: "1.6 bil. km",
travel: "7 years",
},
],
This is what the page code looks like:
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import backgroundImage from "../assets/destination/background-destination-mobile.jpg";
import planet from "../assets/destination/image-moon.png";
// import data from "../data/data.json";
import { data } from "../data/data";
export const Wrapper = styled.div`
height: 100vh;
width: 100vw;
background-image: url(${backgroundImage});
background-repeat: no-repeat;
background-size: cover;
display: flex;
flex-direction: column;
align-items: center;
`;
export const Title = styled.div`
margin-top: 6rem;
color: white;
display: flex;
letter-spacing: 2px;
white-space: nowrap;
`;
export const ImageContainer = styled.div`
width: 80%;
display: flex;
justify-content: center;
align-items: center;
& img {
height: 130px;
width: 130px;
}
`;
export const PlanetChoose = styled.div`
/* background-color: red; */
width: 90%;
display: flex;
justify-content: space-around;
margin-top: 10px;
& p {
color: #d0d6f9;
cursor: pointer;
}
`;
export const ImageTest = styled.img`
width: 150px;
height: 150px;
`;
function Destination() {
const [toggle, setToggle] = useState("");
return (
<Wrapper>
<Title>
<p style={{ marginRight: "10px", color: "grey", fontWeight: "bold" }}>
01
</p>
<p>PICK YOUR DESTINATION</p>
</Title>
<ImageContainer>
//HERE I WANT TO PASS URL FROM MAP
<img src={planet} alt="planet"></img>
</ImageContainer>
<PlanetChoose>
{data.destinations.map(({ name, images }) => {
return (
<>
<p onClick={() => setToggle(name)}>{name}</p>
</>
);
})}
</PlanetChoose>
<h1>{toggle}</h1>
</Wrapper>
);
}
export default Destination;
When I press the 'p' tag the corresponding header and the rest of the data within the mapping is displayed. The question, however, is how to move the url of an image that is outside the mapping in the ImageContainer?
CodePudding user response:
Set the entire object into your toggle
state and either conditionally render the <h1>
and <img>
or use placeholder values, eg
const [ toggle, setToggle ] = useState({
name: "",
images: {
png: somePlaceholderImage
}
});
return (
<Wrapper>
{/* <Title>...</Title> */}
<ImageContainer>
<img src={toggle.images.png} alt="planet" />
</ImageContainer>
<PlanetChoose>
{data.destinations.map(dest => (
<p
key={dest.name}
onClick={() => setToggle(dest)}
>{dest.name}</p>
))}
</PlanetChoose>
<h1>{toggle.name}</h1>
</Wrapper>
);
CodePudding user response:
You need to do 2 things. First, you need to import the entire image directory into the component file as a single variable. Second, you need to access the correct image by parsing the data file and the value of the "toggle" state.
This first step is important since you cannot access files with just a path string in the JSX. You have to import it so that it is included in the bundle, and then you can import images from that directory later. You can import an entire directory into a variable like this:
import images from '../assets/destination';
Now we can use the moon file, for example, like this:
<img src={images["image-moon.png"]} alt="planet" />
To integrate this into your component, all we have to do is manipulate the toggled planet name so that we can access the right file. We can do that with a simple memo hook that returns the formatted image name (or an empty string, so that the image can be conditionally rendered).
import React, { useState, useEffect, useRef, useMemo } from "react";
import styled from "styled-components";
import backgroundImage from "../assets/destination/background-destination-mobile.jpg";
import { data } from "../data/data";
import images from '../assets/destination';
function Destination() {
const [ toggle, setToggle ] = useState("");
const imageName = useMemo(() =>
toggle.length ? `image-${toggle.toLocaleLowerCase()}.png` : ""
, [toggle]);
return (
<Wrapper>
<Title>
<p style={{ marginRight: "10px", color: "grey", fontWeight: "bold" }}>
01
</p>
<p>PICK YOUR DESTINATION</p>
</Title>
<ImageContainer>
//HERE I WANT TO PASS URL FROM MAP
{imageName.length && <img src={images[imageName]} alt="planet" />}
</ImageContainer>
<PlanetChoose>
{data.destinations.map(({ name, images }) => (
<p onClick={() => setToggle(name)}>{name}</p>
)}
</PlanetChoose>
<h1>{toggle}</h1>
</Wrapper>
);
}