dynamically load an image as a prop in react - reactjs

I am trying to load images dynamically in react and pass them as props. I have a data.json file that is basically an array of article objects.
title:"article1"
headline:"headline1"
image:"/src/images/articleimage1"
articleContent:"ipsum lorem"
in the first component I map through the array and return a "card" with props
const featuredArticles = imageCardArray.map(elem => <ImageCard
title={elem.title}
headline = {elem.headline}
image= {elem.image}
/>)
return (
<div className ="center">
{featuredArticles}
</div>
then I use those props in the card component itself. It all works perfectly except for the images
function ImageCard(props) {
return (
<div className="imageCard">
<Card>
<CardActionArea>
<CardMedia
component="img"
image={props.image}
title={props.title}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{props.title}
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
{props.headline}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" varient="outlined">
Artigo completo
</Button>
</CardActions>
</Card>
</div>
);
}
export default ImageCard;
any ideas how to load these images? the card component is from material UI if it helps. (it says in the docs that the image property just accepts a string)
I can get the image to load in the card by importing it at the top and then image = {image}, but of course then it is not dynamic and all the cards have the same image. please help!! thanks

You need to import the image from directory at top
import ArticleImg1 from 'image path';
and then construct your array of objects like this
{
title:"article1"
headline:"headline1"
image:ArticleImg1
articleContent:"ipsum lorem"
}
If I understand your question correctly it will work.

the answer is here https://medium.com/react-courses/5-top-methods-to-import-and-load-images-dynamically-on-cra-react-local-production-build-855d3ba3e704
you need to have in your json just the file name for the image, not the full path.
title:"article1"
headline:"headline1"
image:"articleimage1"
articleContent:"ipsum lorem
then in the card component:
you can either assign the resource to a component ...
const Image = require( '/src/images/'+ props.image);
and in the JSX
<img className="card-img-top" src={ Image } alt="image not found" />
or do the require in the jsx
<img className="card-img-top" src={ require( '/src/images/'+ props.image) } alt="image not found" />
assumption made that all images will be in the same folder...

Related

Gatsby.js issue with frontmatter in graphql

Looking for some help with this issue I have when trying to render the frontmatter for my project list. Essentially, it's not able to "detect frontmatter" nor "AllMdx", but when I query in graphql locally there is no issue. I get the information I need from the query, except I cannot grab the image.
This is the start of my .mdx file, where I define the image, I also tried other variations:
image: "../images/icon.png"
image: ../images/icon.png
image: icon.png
None seem to work.
MT.mdx start of file
---
slug: "/projects/MT"
date: "2019-09-04"
title: "MT"
image: "icon.png"
---
Projects.jsx
import React from "react"
import {ContentContainer} from "../components/Common/Container";
import { StaticQuery, graphql } from "gatsby";
import Card from '#mui/material/Card';
import CardContent from '#mui/material/CardContent';
import CardMedia from '#mui/material/CardMedia';
import Typography from '#mui/material/Typography';
// import { Button, CardActionArea, CardActions } from '#mui/material';
export default function Projects() {
return (
<StaticQuery
query={graphql`
query ProjectsQuery {
allMdx(filter: { fileAbsolutePath: { regex: "/projects/" } }) {
nodes {
frontmatter {
image
slug
title
date
}
excerpt
}
}
}
`}
render={data => (
<ContentContainer>
{data.allMdx.nodes.map(({ frontmatter, excerpt }) => (
<Card sx={{ maxWidth: 360 }}>
<CardMedia
component="img"
height="180"
image={frontmatter.image}
alt="placeholder"
/>
<CardContent>
<Typography gutterBottom variant="h4" component="div">
{frontmatter.title}
<br/>
{frontmatter.slug}
<br/>
{frontmatter.date}
<br/>
{excerpt}
</Typography>
</CardContent>
</Card>
)
)}
</ContentContainer>
)}
></StaticQuery>
)}
Result in localhost
My bet is that the path of the image is not correct.
You are passing a full_DCD.png but that path I'm not sure if it's correct (it will rely on your project structure). This assumes that there's a full_DCD.png image at localhost:8000/full_DCD.png but it looks like it should be somewhere inside /projects/MT/full_DCD.png but as I said, without knowing your project structure it's difficult to guess.
Try spotting the valid image path where the image is located (i.e: checking the /public folder or playing around with the URL to get the image).
Maybe you just simply need to concatenate the project slug, like:
{
data.allMdx.nodes.map(({ frontmatter, excerpt }) => (
<Card sx={{ maxWidth: 360 }}>
<CardMedia
component="img"
height="180"
image={`${frontmatter.slug}${frontmatter.image}`}
alt="placeholder"
/>
<CardContent>
<Typography gutterBottom variant="h4" component="div">
{frontmatter.title}
<br />
{frontmatter.slug}
<br />
{frontmatter.date}
<br />
{excerpt}
</Typography>
</CardContent>
</Card>
));
}
Depending on your structure, you just may need to add image={`/${frontmatter.image}`}.

Conditional rendering of parent component in React

I need to return either Porover or Card depending on the condition with the same children content. This can be done by taking the children content into a separate component and returning it like this:
true ? <Popover><ChildrenContent props={props}/></Popover>
: <Card><ChildrenContent props = {props}/></Card>
But it seems to me that this is not the best solution in this case
<Popover dataCy="complexValidation">
<Section marginBottom={3}>
</Section>
<Flex flexDirection="column" gap={3}>
{validations.map((validation) => (
<Flex.Item key={validation.text}>
<Flex alignItems="center">
<Icon name="check_circle" size="large" color={validation.isSuccess ? 'positive' : 'negative'} />
<Flex.Item>
<Typography variant="bodyText2" component="span">
{validation.text}
</Typography>
</Flex.Item>
</Flex>
</Flex.Item>
))}
</Flex>
</Popover>

How to show a HTMLTag inside <CardHeader> Material UI Component

I am using React Material UI version 4.9.5 and React version 16.13.
Inside CardHeader tag i need to show 2 buttons. I tried placing buttons inside CardHeader tag but they dont show up. I placed the buttons inside title attribute of CardHeader but it shows buttons html code.
How to show HTML tag inside the CardHeader tag?
This is the part of code:
<div className={classes.root}>
<Card elevation={2} >
<CardHeader title= 'New Clin' className = {classes.cardHeaderClass}></CardHeader>
<CardContent className={classes.formContainer} >
<Divider className={classes.divider} />
<Grid container>
like in material ui card example, you need to add your button in action cardHeader props like for example:
<CardHeader
avatar={
<Avatar aria-label="recipe" className={classes.avatar}>
R
</Avatar>
}
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title="Shrimp and Chorizo Paella"
subheader="September 14, 2016"
/>

returning results of Google Distance Matrix API call

I'm developing a React app for tracking food trucks. I'm trying to write code for retrieving the distance between a user's location and a food truck. I'm using the Google Distance Matrix API for this. Here is the function:
const getTruckDistance = (userLocation, truckLocation) => {
fetch(
`https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=${userLocation}&destinations=${truckLocation}&departure_time=now&key=${GOOGLE_API_KEY}`
)
.then(res => res.json())
.then(data => {
console.log(data.rows[0].elements[0].distance.text);
// return data.rows[0].elements[0].distance.text;
});
};
I then map over the trucks held in Redux state and apply this function to them:
{
props.trucks && (
<div className="card-div">
<h3 className="trucks-category">Nearby Trucks</h3>
<div className="trucks-div">
{props.trucks.slice(0, 3).map(truck => (
<Card className="truck-card">
<CardActionArea>
<CardMedia
className={classes.media}
image={truck.image}
title="Contemplative Reptile"
/>
<CardContent>
<Typography
className="truck-name"
gutterBottom
variant="h5"
component="h2"
>
{truck.name}
</Typography>
<Typography className="cuisine-type" component="h3">
{truck.cuisine_type}
</Typography>
<Typography className="distance-plus-rating" component="h3">
{console.log(
`props.location: ${
props.location
}, truck.current_location: ${truck.current_location}`
)}
{console.log(
getTruckDistance(props.location, truck.current_location)
)}
</Typography>
</CardContent>
</CardActionArea>
</Card>
))}
</div>
</div>
);
}
When I do this, I am getting the console.log from the getTruckDistance fn without issue. It shows me the distance between the user location and each truck being mapped over.
However, when I try to log the actual result of calling the fn and passing in user location (props.location) and truck location (truck.current_location), I am getting undefined logged to the console.
I need this info to show the distance between truck and user and render that to the screen along with each truck. What am I doing wrong here?
Here's a picture illustrating the results of my console.log's:
Where I'm getting undefined, I should be getting the actual distances: 5.8 mi, 1.4 mi and 5.4 mi, respectively.

AppBar Material UI questions

I'm pretty new to the Material UI Library but I really like it so far! However, i am having an issue with the AppBar component overlaying over my other content. I currently have <AppBar /> and <myComponent /> in my App.js render method. Here is the code snippet for that:
render(){
return (
<div>
<AppBar />
<myComponent />
</div>
);
}
This is the code for the myComponent function:
function myComponent(){
return (
<h1>
Hello
</h1>
);
}
However, when I run this code, the "Hello" message is overlaid by the AppBar component. Is there some way to have my hello message (and corresponding code) be displayed under the AppBar? It's a simple question but I would love to figure this out!
You need to add the top margin from top to the component which you have created right below the app bar
I am posting this from mobile if you need code just let me know I will right it for you
You can add paddingTop to the containing div to compensate for the height of the AppBar (64px by default):
render() {
return (
<div style={{ paddingTop: 64 }}>
<AppBar>
<Toolbar>
<Typography variant="title" color="inherit">
Title
</Typography>
</Toolbar>
</AppBar>
<YourComponent />
</div>
);
}

Resources