Reusing markup in reactJS and best practice - reactjs

I am learning react and I am attempting to reuse code (I'm told that's one of the great things about react). I currently have the following markup with the data sets imported like so. I have attempted to loop through the data set using .map but its proving to be difficult. Is there a best practice (slightly discussion focued rather than just answerable as stack overflow outlines, but I'm attempting to learn) when it comes to looping through data. Thanks
JS
import {recommendedActivities3} from '../../data/mocks'
import {recommendedActivities4} from '../../data/mocks'
<Link className={`PageCell recommended`} to={`/places/top-activities/${recommendedActivities3.id}`}>
<div className={`restaurantCard-main recommended`}>
<span className="host-recommendation-text">Host recommended</span>
<div className={`restaurantCard recommended`}>
<img className={`photo activity`} src={recommendedActivities3.image_url} size="small" alt="activities" />
<div className={`restaurantCard-right`}>
<div className="name">{recommendedActivities3.name}</div>
<div className="description"><p>{recommendedActivities3.description}</p></div>
</div>
</div>
</div>
</Link>
<Link className={`PageCell recommended`} to={`/places/top-activities/${recommendedActivities4.id}`}>
<div className={`restaurantCard-main recommended`}>
<span className="host-recommendation-text">Host recommended</span>
<div className={`restaurantCard recommended`}>
<img className={`photo activity`} src={recommendedActivities4.image_url} size="small" alt="activities" />
<div className={`restaurantCard-right`}>
<div className="name">{recommendedActivities4.name}</div>
<div className="description"><p>{recommendedActivities4.description}</p></div>
{/*<CellContent recommendedActivities={recommendedActivities} recHeight={recHeight} normalHeight={normalHeight} />*/}
</div>
</div>
</div>
</Link>
Data
Below I have provided the structure of my data for reference. Not sure if it is necessary.
export const recommendedActivities4 = {
description: 'One of the best spots in SFs Famous: North Beach. Grab a coffee and just people watch for hours!',
id: 'tartine-bakery-and-cafe-san-francisco',
name: 'Tartine Bakery & Cafe',
image_url: 'https://s3-media3.fl.yelpcdn.com/bphoto/vTLu8G86IqIazm7BRqIH4g/o.jpg',
is_closed: false,
url:
'https://www.yelp.com/biz/nopa-san-francisco?adjust_creative=oj0judbJDVIHIVps_GJrXQ&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=oj0judbJDVIHIVps_GJrXQ',
review_count: 4636,
categories: [
{
alias: 'newamerican',
title: 'American (New)',
},
{
alias: 'modern_european',
title: 'Modern European',
},
],
rating: 4,
coordinates: {
latitude: 37.774905,
longitude: -122.437506,
},
transactions: ['restaurant_reservation'],
price: '$$$',
location: {
address1: '560 Divisadero St',
address2: null,
address3: '',
city: 'San Francisco',
zip_code: '94117',
country: 'US',
state: 'CA',
display_address: ['560 Divisadero St', 'San Francisco, CA 94117'],
},
phone: '+14158648643',
display_phone: '(415) 864-8643',
distance: 255.549722789804,
}

So lets say you have some small component that you want to use to just render one recommended activity link. it would look something like this
const RecommendedActivity = ({activity}) => {
return (
<Link className="PageCell recommended" to={`/places/top-activities/${activity.id}`}>
<div className="restaurantCard-main recommended">
<span className="host-recommendation-text">Host recommended</span>
<div className="restaurantCard recommended">
<img className="photo activity" src={activity.image_url} size="small" alt="activities" />
<div className="restaurantCard-right">
<div className="name">{activity.name}</div>
<div className="description"><p>{activity.description}</p></div>
</div>
</div>
</div>
</Link>
)
}
this makes it a reusable component. So then the way you would use it is like so:
first lets make an array of recommended activities to work with const seed = [recommendedActivities3, recommendedActivities4]
now in the render method you would just call the particular component for each element in the array
{ seed.map( (activity, idx) => <RecommendedActivity activity={activity} key={idx}/>)}

Related

How to change img src onmouseover in ReactJs

** I want to change the image src on mouseover, i have added multiple images dynamically.**
const Servicesdata = [
{
ID: "01",
title: "Power Generation",
desc:
" We have rich experience in building thermal, hydro, and combined cycle power plants. We provide customized ready-to-deploy solutions for power plants including total EPC and comprehensive Balance of Plant (BOP) and Flue-gas desulfurization (FGD) solutions.",
imgsrc: "https://www.tataprojects.com/images/Transmission-Line.jpg",
imgsrcHover: "https://www.tataprojects.com/images/Sunbstations-min.jpg"
},
{
ID: "02",
title: "Transmission",
desc:
"We have successfully commissioned more than 13,000 kms of transmission lines across multiple voltage levels including 800kv HVDC projects",
imgsrc: "https://www.tataprojects.com/images/Sunbstations-min.jpg",
imgsrcHover: "https://www.tataprojects.com/images/Sunbstations-min.jpg"
},
{
ID: "03",
title: "Substations",
desc:
"Our optimally designed towers and substation structures allow us to reduce conductor wastage ensuring faster construction and on-time delivery.",
imgsrc: "https://www.tataprojects.com/images/Tower-Manufactaring-Unit.jpg",
imgsrcHover: "https://www.tataprojects.com/images/Sunbstations-min.jpg"
},
{
ID: "04",
title: "Tower Manufacturing Unit",
desc:
"We have a state-of-the-art manufacturing unit to manufacture transmission line towers and structures. The unit is spread across 40 acres of land.",
imgsrc: "https://www.tataprojects.com/images/Smart-Grid-min.jpg",
imgsrcHover: "https://www.tataprojects.com/images/Sunbstations-min.jpg"
}
];
export default Servicesdata;
import react from "react";
import Servicesdata from "../data/Servicesdata";
const Services = () => {
return (
<>
<section className="services">
<div className="container mt-5">
<div className="row">
<div className="col-md-12">
<h2 className="text-center heading-style-1">Key Areas</h2>
</div>
</div>
{Servicesdata.map((val, index) => {
return (
<div className="row featurette align-items-center">
<div className="col-md-7">
<h2 className="featurette-heading">{val.title}</h2>
<p className="lead">{val.desc}</p>
</div>
<div className="col-md-5">
<img src={val.imgsrc} className="img-fluid" />
</div>
</div>
);
})}
</div>
</section>
</>
);
};
export default Services;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
We can make use of onMouseOver & onMouseOut event handlers in order to toggle the images of the current hovering image.
We can store the ID of the object in the state when we hover on the image of that particular object
And reset it to "" on mouse out
In render we can check the ID in the state with the object id, if they are matching then use imgsrcHover else use imgsrc
const Servicesdata = [{ID:"01",title:"Power Generation",desc:" We have rich experience in building thermal, hydro, and combined cycle power plants. We provide customized ready-to-deploy solutions for power plants including total EPC and comprehensive Balance of Plant (BOP) and Flue-gas desulfurization (FGD) solutions.",imgsrc:"https://www.tataprojects.com/images/Transmission-Line.jpg",imgsrcHover:"https://www.tataprojects.com/images/Sunbstations-min.jpg"},{ID:"02",title:"Transmission",desc:"We have successfully commissioned more than 13,000 kms of transmission lines across multiple voltage levels including 800kv HVDC projects",imgsrc:"https://www.tataprojects.com/images/Sunbstations-min.jpg",imgsrcHover:"https://www.tataprojects.com/images/Sunbstations-min.jpg"},{ID:"03",title:"Substations",desc:"Our optimally designed towers and substation structures allow us to reduce conductor wastage ensuring faster construction and on-time delivery.",imgsrc:"https://www.tataprojects.com/images/Tower-Manufactaring-Unit.jpg",imgsrcHover:"https://www.tataprojects.com/images/Sunbstations-min.jpg"},{ID:"04",title:"Tower Manufacturing Unit",desc:"We have a state-of-the-art manufacturing unit to manufacture transmission line towers and structures. The unit is spread across 40 acres of land.",imgsrc:"https://www.tataprojects.com/images/Smart-Grid-min.jpg",imgsrcHover:"https://www.tataprojects.com/images/Sunbstations-min.jpg"}];
const { useState } = React;
const Services = () => {
//Store the currently hovered object's id in the state
//Initially it'll be ""
const [currentHoveredId, setCurrentHoveredId] = useState("");
//On mouse over update the id with the cuurent object's ID
const onMouseOver = (id) => {
setCurrentHoveredId(id);
}
//On moving the cursoe out of the image, then reset it to ""
const onMouseOut = () => {
setCurrentHoveredId("");
}
return (
<section className="services">
<div className="container mt-5">
<div className="row">
<div className="col-md-12">
<h2 className="text-center heading-style-1">Key Areas</h2>
</div>
</div>
{Servicesdata.map((val, index) => {
return (
<div className="row featurette align-items-center" key={val.ID}>
<div className="col-md-7">
<h2 className="featurette-heading">{val.title}</h2>
<p className="lead">{val.desc}</p>
</div>
<div className="col-md-5">
{/* Toggle the image source based on the result of the id in state and the id of the current object */}
<img src={currentHoveredId === val.ID ? val.imgsrcHover : val.imgsrc}
className="img-fluid"
onMouseOver={() => {onMouseOver(val.ID)}}
onMouseOut={onMouseOut}/>
</div>
</div>
);
})}
</div>
</section>
);
};
ReactDOM.render(<Services />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="react"></div>
I have used your code as it is just added the corresponding event handlers and the state as mentioned above.
Make the following modifications in the code:
this.setState({
servicesData: ServicesData;
})
And call the below function on mouseover,passing the index and the newSrc as parameter:
imgSrcUpdate(index, newSrc) {
let oldData = this.state.servicesData;
oldData[index][src] = newSrc;
this.setState({
servicesData: oldData
})
}
Instead of this:
{Servicesdata.map((val, index) => { ...
Use :
{this.state.servicesData.map((val, index) => {....

Why is my image not showing in my react project

I'm currently following a tutorial and I tried to render some images coming from an array as shown in the tutorial but none of the images show up in the browser.
This is the component showing how I went about that.
import React from 'react';
export default function MasonryPost ({post, tagsOnTop}) {
const style = {backgroundImage: `url("${require(`../../assests/images/${post.image}`)}")`}
return (
<a className="masonry-post overlay" style={style} href={post.link}>
<div className="image-text">
<div>
<h2 className="image-title">{post.title}</h2>
</div>
</div>
</a>
)
}
When I inspect it in the browser, instead of the url link, it shows "object module"
This is where the images ought to come from
import moment from 'moment'
export default [
{
title: 'Do you want to code?',
date: moment().format('MMMM DD, YYYY'),
categories: ['Beginning your journey'],
link: '#',
image: 'journey.jpg'
},
{
title: 'Using AWS S3 for Storing Blog Images',
date: moment().format('MMMM DD, YYYY'),
categories: ['Cloud'],
link: '#',
image: 'cloud.jpg'
},
{
title: 'Highest paying Programming Languages in 2020',
date: moment().format('MMMM DD, YYYY'),
categories: ['Tect Culture', 'Tech News'],
link: '#',
image: 'Tech.jpg'
},
{
title: 'Brain Hacks For getting enough rest',
date: moment().format('MMMM DD, YYYY'),
categories: ['Brain Health'],
link: '#',
image: 'Brain.jpg'
},
{
title: 'How to manage time while you Program',
date: moment().format('MMMM DD, YYYY'),
categories: ['Time Management'],
link: '#',
image: 'Time.jpg'
},
{
title: 'Brain Hacks For Learning to Program',
date: moment().format('MMMM DD, YYYY'),
categories: ['Brain Health'],
link: '#',
image: 'Brain.jpg'
},
]
I saw a few things online about the issue coming from webpack.config.js, I tried most of their solutions but the problem still persists.
I have no idea what to do again. I would appreciate anyone's help.
You need to provide path to the file. What you are doing is providing the data of the file itself. You can also convert them to base64 form. But i guess, only removing the require call will be sufficient.
You don't need to require each image. You can simply use:
const style = {backgroundImage: `url("/assests/images/${post.image}")`}
Try this approach,
function MasonryPost({ post }) {
const style = {
background: `url("../assets/images/${post.image}") no-repeat`,
height: "200px",
width: "230px"
};
return (
<div className="masonry-post overlay" style={style} href={post.link}>
<div className="image-text">
<div>
<h2 className="image-title">{post.title}</h2>
</div>
</div>
</div>
);
}
Working code:- https://codesandbox.io/s/competent-bash-o34kd?file=/src/App.js:1452-1851
you can use this code instead of your code:
import React from 'react';
render(){
return (
<div style ={{backgroundImage: url("YourPath")}}>
<a href={post.link}>
<div className="image-text">
<div>
<h2 className="image-title">{post.title}</h2>
</div>
</div>
</a>
</div>
)
}

Adding an image and an anchor tag to an element within an array using props in React

While creating cards and using props in React.js I need to add an anchor tag(website:) and an image (image:) within a few elements in an array but am unable to figure out how. Of course, as seen below simply just adding an anchor tag etc does not work. Any help would be appreciated.
const projects = [
{
id: 1,
image: <img src="https://picture.jpg" alt="Coaching Website">
name: "Personal Coaching Website",
meaning:"A comprehensive website for a personal health and wellness coach"
website:
},
Rather than defining elements in an array, use the values, and map into the properties of the element.
const projects = [
{
id: 1,
image: "https://picture.jpg",
name: "Personal Coaching Website",
meaning: "A comprehensive website for a personal health and wellness coach",
website: "https://www.samplewebsite.com"
}
];
export default function App() {
return (
<div>
{projects.map(project => {
return (
<div>
<img src={project.image} />
<a href={project.website} />
</div>
);
})}
</div>
);
}

Basic usage of keys - Extract single item prop from data list

In React I have an array of projects (only 2 in this example). Each project has:
key
name
info
I would like to be able to render, for example, only one project name. Everything I have tried gives me the whole list. I am confused on the format I need to use to:
Set up my ID
Tell React what specific ID I want to render
I have tried creating different formats (Try number 1 & 2) using .map
function ProjectList() {
const projects = [
{
id: 0,
name: "Shop",
date: "2019",
info: "info of 1",
},
{
id: 1,
name: "Hotel",
date: "2019",
info: "info of 2",
},
]
const findProjectInfo = projects.map (project =>(
<div key={1}>
<h2 key={project.ID}>
{project.info}
</h2>
</div>
))
return (
<div>
<div className='TRY NUMBER ONE' key={1}>
{projects.map (project=> (
<div key={project.ID}>
<div> {project.name}</div>
<div> {project.info}</div>
</div>
))}
</div>
<div className='TRY NUMBER TWO' key={1}>
{findProjectInfo}
</div>
</div>
)
}
export default ProjectList
Everything I tried gives me the two items of my list and not only the 1st one as I would want.
Try something like that:
const projects = [
{
id: 0,
name: "Shop",
date: "2019",
info: "info of 1",
},
{
id: 1,
name: "Hotel",
date: "2019",
info: "info of 2",
},
];
function ProjectList() {
const [selectedProject,setSelectedProject] = React.useState(0);
return (
<React.Fragment>
<div>Select Project</div>
<button onClick={()=>setSelectedProject(0)}>Project 1</button>
<button onClick={()=>setSelectedProject(1)}>Project 2</button>
<br/><br/>
<div><b>Project name: </b>{projects[selectedProject].name}</div>
<div><b>Project date: </b>{projects[selectedProject].date}</div>
<div><b>Project info: </b>{projects[selectedProject].info}</div>
</React.Fragment>
);
}
ReactDOM.render(<ProjectList/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
.map will always return you an array with the same size as the original. What you want to do is find a specific element, like this:
const project1 = findProjectInfo.find(project => project.id === 1);
This will return a single object instead of an array, which you can then render:
<div>
<div>{project.name}</div>
<div>{project.info}</div>
</div>
More info on Array.prototype.find() here.
The key prop is not to be used for anything related to this. It is a special prop that helps React know when components change, and only usually needed when you want to render arrays (like when you use .map), or in a few more advanced cases.
You are simply iterating through your array, that is why you are getting every element from array as result.
You need to first filter your array using provided ID and then you can iterate using map,
{projects
.filter(projects => projects.id === providedID) //providedID can be stored in state
.map(project => (
<div key={project.id}>
<h2 key={project.id}>{project.info}</h2>
</div>
))
}
Demo
Note: Don't use key like this,
<div className='TRY NUMBER ONE' key={1}>
Also make sure you don't repeat the key for multiple elements.
Update
Changing state and getting project details based on selected project ID.
Demo1

Display images dynamically using map() in react not working

I want to display images in the sports array using map(). but not working
<div className="row">
{this.state.sports.map(function(sport, index){
return (
<div className="col-md-3" key={index}>
<h3 className="text-center">{this.state.sports.name}</h3>
<img src={ require('./../assets/images/'+ {this.state.sports.name} +'.jpg') } width="300px" height="180px" />
<button className="btn btn-info btn-sm" type="submit" onClick={this.join_in_sport} >JOIN</button>
</div>
)
}.bind(this))}
</div>
The problem seems to lie in how you are building the pathname for your image. Same for your <h3> tag.
src={ require('./../assets/images/'+ {this.state.sports.name} +'.jpg') }
If this.state.sports is an array, and not an object, then it can't possibly have a name key. I think you meant to print the current objects name for each iteration in your map().
So try:
<h3 className="text-center">{this.state.sports.name}</h3>
<img src={ require('./../assets/images/'+ {sport.name} +'.jpg') } width="300px" height="180px" />
This is assuming your array looks something like:
[
{name: "foo"},
{name: "bar"}
]
I have encountered the same problem,
the image folder in src doesn't work.
I moved the image folder to public and it works fine.
function App() {
const moviesData = [
name: "Terminator: Dark Fate",
img: "./badboy3.jpg", //image in public folder
},
];
const movieList = moviesData.map((movie, i) => {
return <Movie key={i} movieName={movie.name} movieImg={movie.img} />;
});
return (
<div>
{movieList}
</div>
);
}
export default App;
I was following the React beginners tutorial tried to call images dynamically by importing them as variables but this simply didn't work when trying to call them in another file (App.js) using the .map() function. Code below:
import katieImg from "../images/Katie.png";
import starImg from "../images/Katie.png";
export default [
{
img: { katieImg },
star: { starImg },
rating: "5.0",
reviewCount: 6,
location: "USA",
title: "Life Lessons with Katie Zaferes",
price: 136,
},
];
So instead I had to get rid of the dynamically imported variables and put the images folder in the public folder. This worked. Code below:
export default [
{
img: "../images/Katie.png",
star: "../images/Star.png",
rating: "5.0",
reviewCount: 6,
location: "USA",
title: "Life Lessons with Katie Zaferes",
price: 136,
},
];

Resources