I now have two slightly more complicated React projects under my belt. The first, an AirBnB Experiences Clone app, I did as a code-along project with Scrimba. (Link to repo.)
airbnb Experiences Clone
This airbnb experiences clone app pulled in a data file of "experiences" objects, converted them to an array of objects, and then mapped each object to Card() component, which output each objects relevant data in formatted html. The entire project was then styled with CSS.
Here is the code from my container app - App.js:
import logo from './logo.svg';
import Top from "./components/Top"
import Card from "./components/Card"
import photoexperience from "./images/katie-zaferes.png"
import CardData from "./data"
// note had to find custom image solution - https://delftstack.com/howto/react/react-img-src/
function App() {
//note assign key to eliminate key error
// pass entire object to Card()
const cardElements = CardData.map((card)=>{
return <Card
key={card.id}
card={card}/>
})
// console.log("cardElements: ", cardElements)
return (
<div>
<Top />
<div className="experience-photos">{cardElements}</div>
</div>
);
}
export default App;
Here is the code from the Card.js component:
import React from "react"
import photoexperience from "../images/katie-zaferes.png"
import star from "../images/star.png"
export default function Card(props){
let badgeText
if(props.card.openSpots===0){
badgeText = "Sold-Out"
} else if (props.card.country === "Online"){
badgeText = "Online"
}
console.log(props.card)
return <div className="experience-listing">
{/* conditional display if there is badge text*/}
{badgeText && <div className="experience-status">{badgeText}</div>}
<img className="experience-img" src={props.card.coverImg} alt={props.card.title}></img>
<div className="review-div">
<img className="star-img" src={star} alt="star"></img>
<span className="rating">{props.card.stats.rating}</span>
<span className="review-count grey"> ({props.card.stats.reviewCount}) * </span>
<span className="country grey"> {props.card.location}</span>
</div>
{/* end review div */}
<p className="experience-heading">{props.card.title}</p>
<p className="experience-price"><span className="bold">From ${props.card.price}</span> / person</p>
</div>
{/* holds one photo */}
// holds all photos
}
and here is a snippet of the data file:
export default [
{
id: 1,
title: "Life Lessons with Katie Zaferes",
description: "I will share with you what I call \"Positively Impactful Moments of Disappointment.\" Throughout my career, many of my highest moments only came after setbacks and losses. But learning from those difficult moments is what gave me the ability to rise above them and reach my goals.",
price: 136,
coverImg: "katie-zaferes.png",
stats: {
rating: 5.0,
reviewCount: 6
},
location: "Online",
openSpots: 0,
},
<...>
]
The main problem that I ran into in this tutorial was understanding where image files needed to be stored in order to be accessible. I was able to search for and find this resource, which explained that if you want to import a local image - the image needs to be stored in a subfolder of the src folder in your App. If you are using a data file with photo file names, like I was, then you need to store those images in the public folder, or in a subfolder ("images" for example.)
Travel Journal App
Next, I used the basic techniques of the airbnb experiences clone to write up a small travel journal app using React. Each travel journal entry displays a location image, link to Google maps, and short description. The format is essentially the same as above in terms of structure. (Link to repo.)
Here is the container app code:
import TravelData from "./data"
import TripCard from './components/tripcard';
import Header from "./components/header"
function App() {
// get data out of file and into object
const tripElements = TravelData.map(
(trip) =>{
// return <TripCard title={trip.title}/>
return <TripCard key={trip.id} trip={trip} />
}
)
console.log(tripElements)
return (
<div>
<Header />
<div className="trip-listing">{tripElements}
</div>
</div>
);
}
export default App;
The TripCard.js component code:
import React from "react"
import MapIcon from "../images/map-pin-solid.svg"
export default function TripCard(props){
let image = props.trip.imageURL
console.log(image)
return <div className="trip-card"><h1 className="trip-title">{props.trip.title}</h1>
<img className="trip-image" src={props.trip.imageURL} alt={props.trip.title}></img>
<div className="location">
<img src={MapIcon} className="location-icon" alt="map pin icon"></img>
<h2 className="trip-location">{props.trip.location}</h2><a href={props.trip.googleMapsUrl}className="location-link">View on Google Maps</a></div>
<span className="trip-date">{props.trip.visitDate}</span>
<p className="trip-description">{props.trip.description}</p>
</div>
}
and a snippet of the data file object -
export default [
{
id: 1,
title: "Volcanos National Park",
location:"USA",
googleMapsUrl:"https://goo.gl/maps/dPk4XiWD7roXFjhx8",
visitDate:"June 2010",
description:"Unique destination to spot live lava flows, lava tubes & glowing craters is popular with tourists.",
photographerCredits:"https://unsplash.com/photos/xfSdarS1wus",
imageURL:"https://images.unsplash.com/photo-1509780764860-beca5b971c4b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80"
},
<...>
]
Top comments (2)
Great example of going beyond the tutorials to get some real learning done and come across your own issues!
One small tip regarding the post formatting, three back-ticks followed by language will make your code chunks prettier to look at.
Regarding the code itself, I've sent a pull request - accepting it or not is entirely up to you, just wanted to provide a small impromptu code review for styling and consistency across code base.
Have a good one!
Thank you for the tip - I made the code snippet formatting change and it looks much better.
I saw your mini code review and I appreciate you taking the time. Can I ask what the advantage is of switching to
"const Header = () => " instead of using "export default function"?