Image on Material UI CardMedia - reactjs

I´m having some troubles on getting an image from props on a CardMedia image:
<Card className={classes.card}>
<CardMedia
className={classes.img}
image={this.props.recipe.thumbnail}
/>
<CardContent className={classes.content}>
<Typography gutterBottom variant="headline" component="h2">
{this.props.recipe.title}
</Typography>
<Typography component="p">
{this.props.recipe.ingredients}
</Typography>
</CardContent>
<CardActions>
<Button
href={this.props.recipe.href}
Recipe
</Button>
</CardActions>
</Card>
It just doesnt render at all the images; all the other props values are rendered as they has to.
Also as Material UI I had specified the CardMedia height on a JS css.
Does anyone knows why this happens?

I had the Same Issue. Finally Got it Working doing this:
const styles = {
media: {
height: 0,
paddingTop: '56.25%', // 16:9,
marginTop:'30'
}
};
<CardMedia
className={classes.media}
image={require('assets/img/bg2.jpg')} // require image
title="Contemplative Reptile"
style={styles.media} // specify styles
/>
You can also check :
https://codesandbox.io/s/9zqr09zqjo - No option to load images . The image location is my local

I have read the docs and also notice that you have to specify the height to display images. While they say you should create a component with style I feel that a simpler way of doing it is by using the style prop directly:
<CardMedia
style={{height: 0, paddingTop: '56.25%'}}
image={project.image}
title="lorem ipsum"
/>
The other options would be to create a style object first and then render the component withStyle as the docs said:
const styles = {
card: {
maxWidth: 345,
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9
},
};
function SimpleMediaCard(props) {
const { classes } = props;
return (
<div>
<Card className={classes.card}>
<CardMedia
className={classes.media}
image="/static/images/cards/contemplative-reptile.jpg"
title="Contemplative Reptile"
/>
</Card>
</div>
);
}
export default withStyles(styles)(SimpleMediaCard);

to set fallback image on CardMedia, you can try this:
import FALLBACK_IMAGE from 'src/assets/images/fallback_image.png';
const onMediaFallback = event => event.target.src = FALLBACK_IMAGE;
<CardMedia
component="img"
className={classes.media}
image="/static/images/cards/contemplative-reptile.jpg"
title="Contemplative Reptile"
onError={onMediaFallback}
/>

I was facing the same issue.
A good workaround would be to use the 'img' element along with the 'src' attribute inside the CardMedia body instead of passing it as an attribute to the CardMedia.
<CardMedia>
<img src={this.props.recipe.thumbnail} alt="recipe thumbnail"/>
</CardMedia>
And while passing the props to the class I sent the image path as an object. In your case, suppose recipe is an object with thumbnail as one of the attributes. Then in the parent class, I would write the prop as:
...
recipe = {
.
.
thumbnail: require('assets/images/img1.jpg'),
//make sure the path of the image is relative to parent class where you are defining the prop
.
.
}
...
Here I am sending the path of the image as an object. This worked for me.

After updating from 4.9 => 4.12
add component="img" prop
(it had 0 height in DOM after the update despite setting it to 200px)
<CardMedia className={classes.pageMedia} component='img' image='/static/img.jpg' />

In my case it worked after changing the value of height other than 0 in the style
Not Worked:
const styles = {
card: {
maxWidth: 345,
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9
},
};
Worked:
const styles = {
card: {
maxWidth: 345,
},
media: {
height: "300px" or "10em",
paddingTop: '56.25%', // 16:9
},
};

Try using src property instead of img property

Related

How to avoid initial lag after input using Material UI

Context
I have a carousel of MUI cards for a website that I'm building that is a box using a stack as it's underlying component. A problem that's come up is that whenever I try to scroll, there's at least a 4 second lag before seeing any new render. I tried
cropping down the images
compressing them
converting to .webp's
moving the logic into one place instead of passing props
Thouhgts
Memoizing the component works as a band-aid after the initial lag and
it scrolls as it should after but I'm assuming that's not the correct way
to do this.
(Idea) After looking back into the docs for an alternative I figured
virtualizing the list might work as well
Would probably be easier to just write them out by hand
Cut off a lot of the unnecessary bits
Index.tsx snippet mapping through data
<Box
component={Stack}
direction="row"
spacing={5}
>
{carouselData.map((item: CarouselProps) => (
<CreativeCarousel
src={item.src}
/>
))}
</Box>
Carousel Component
//Consistent typing for properties
export type CarouselProps = {
src: StaticImageData;
};
const CreativeCarousel = (props: CarouselProps) => {
return (
<Card sx={{ maxWidth: 300, minWidth: 300, height: "100%" }}>
<CardMedia component="img" height="75" image={props.src.src} />
</Card>
);
};
export default CreativeCarousel;
Troubleshooting
The lag went away after removing the <CardMedia /> so my guess is that rerendering full-res images for every frame of scrolling isn't the most optimal move.
Solution
But replacing the underlying component from the standard html img to an optimized Next.js Image most definitely was. I was under the impression that I needed to pass a component as a property or else I'd need to use an img like what was used in the example. I only found out later that I could also pass react nodes as children in the API page.
const Carousel = () => {
return carouselData.map((item) => (
<Card
key={item.heading}
sx={{ maxWidth: 300, minWidth: 300, height: "100%", mx: 4 }}
>
<CardMedia sx={{ width: "100%", height: "auto" }}>
<Image
alt={item.heading}
src={item.src}
layout="responsive"
/>
</CardMedia>
</Card>
));
};
export default Carousel;

Warning "Each child in a list should have a unique "key" prop' even with the key present (React + Material UI)

I am trying to fetch data from a JSON file using map function, but I keep getting this error 'Each child in a list should have a unique "key" prop' even though I set the key={facts.id}. Please how can I get rid of this error? Every other thing is working fine.
import React from "react";
import ResponsiveAppBar from "./ResponsiveAppBar";
import Typography from "#mui/material/Typography";
import { styled } from "#mui/material/styles";
import Box from "#mui/material/Box";
import Paper from "#mui/material/Paper";
import Grid from "#mui/material/Grid";
import Facts from "../sources/facts.json";
import Data from "../sources/credits.json";
const Learn = () => {
const Item = styled(Paper)(({ theme }) => ({
backgroundColor: theme.palette.mode === "dark" ? "#1A2027" : "#fff",
...theme.typography.body2,
padding: theme.spacing(2),
textAlign: "center",
color: theme.palette.text.secondary,
}));
return (
<div>
<ResponsiveAppBar />
{Facts &&
Facts.map((fact) => {
return (
<Box sx={{ flexGrow: 1 }} style={{
marginTop:50}}>
<Grid
container
spacing={2}
elevation={9}
justifyContent="center"
style={{ margin: "auto" }}
>
<Grid item xs={8} >
<Item key={fact.id} >
<Typography
variant="h5"
gutterBottom
component="div"
style={{ fontWeight: 600 }}
>
{fact.id}. {fact.title}
</Typography>
<Typography variant="body1" gutterBottom>
{fact.content}
</Typography>
</Item>
</Grid>
</Grid>
<br />
<br />
</Box>
);
})}
</div>
);
};
export default Learn;
You should assign key to the first element you return :
return (
<Box key={fact.id} sx={{ flexGrow: 1 }} style={{
marginTop:50}}>
I got it working by adding an index to the map function parameter, and setting the key to equal the index.
Facts.map((fact, i) => {
return (
<Box sx={{ flexGrow: 1 }} style={{
marginTop:50} key={i}>

Nextjs Thumbs is not showing in react-responsive-carousel while using next image

I am using react-responsive-carousel to show the image gallery of products with thumbs, while I am using a simple img HTML element the thums show up but while I use next image the thumbs vanish, I wonder how can I fix this issue.
<Carousel showThumbs>
{images.map((image) => (
<Box>
<Badge
badgeContent="30%"
color="primary"
anchorOrigin={{
vertical: 'top',
horizontal: 'left',
}}
sx={{
position: 'absolute',
top: '2rem',
left: '2.5rem',
}}
/>
{/* <img src={image.original} alt="ok" /> this word just fine*/}
{/* this does not show up thumbs */}
<Image
src={image.original}
alt="piece"
width={image.originalWidth}
height={image.originalHeight}
/>
</Box>
))}
</Carousel>
It's because react-responsive-carousel can't get image list inside custom components, it can only get from tag or tag inside tag. I think nextjs 's Image components count as custom components too.
ref: https://github.com/leandrowd/react-responsive-carousel/blob/master/TROUBLESHOOTING.md
When I implement Slider with SwipeableViews, I used pure image like this.
package.json
"dependencies": {
...
"react-swipeable-views": "^0.14.0",
"react-swipeable-views-utils": "^0.14.0",
...
}
slider-carousel-test.js
import SwipeableViews from 'react-swipeable-views';
import { autoPlay } from 'react-swipeable-views-utils';
const AutoPlaySwipeableViews = autoPlay(SwipeableViews);
export default function TestComponent (){
return (
<AutoPlaySwipeableViews
axis='x'
index={activeStep}//for auto
onChangeIndex={handleStepChange}//for user click
enableMouseEvents
>
{
data.map((elem, idx)=>
<Box
component="img"
sx={{
display:'block',
overflow:'hidden',
width:'100%',
}}
src={`https://contents.herokuapp.com/images/content${1+idx}.png`}
alt="No Image"
/>
);
}
</AutoPlaySwipeableViews>
)
}
Because Image from next/image does not provide image for react-responsive-carousel, I recommend you this way...
You need to customize the renderThumbs method.
renderThumbs = {() => (
images.map((image, index) => (
<Image
key={index}
src={image.original}
alt="piece"
width={image.originalWidth}
height={image.originalHeight}
/>
)))}

How to apply fontSize to CardHeader title in MUI?

I want to change the title in CardHeader to 16px. I tried changing theme in App.js but it does not seem to work
const theme = createMuiTheme({
typography: {
useNextVariants: true,
overrides: {
MuiCardHeader: {
titleTypographyProps: {
variant:'h2'
}
}
}
}
);
In the component:
<CardHeader
action={
<IconButton color="inherit">
<MoreHorizIcon />
</IconButton>
}
title="Titletext"
/>
The title font still does not change. What do I need to do to fix this?
you cant target the header class or id and change fontSize or
pass as props
titleTypographyProps={{variant:'h1' }}
that object acepts:'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'subtitle1', 'subtitle2', 'body1', 'body2', 'caption', 'button', 'overline', 'srOnly', 'inherit', "display4", 'display3', 'display2', 'display1', 'headline', 'title', 'subheading'
in your code it would be
<CardHeader
action={
<IconButton color="inherit">
<MoreHorizIcon />
</IconButton>
}
titleTypographyProps={{variant:'h1' }}
title="Titletext"
/>
I know this is quite old post now, but for future references anyone who stumbles upon this question might take a look at: https://github.com/mui-org/material-ui/issues/7521
Basically, we can use the classes property, which takes key/value pairs, and can add style to parts of the <ContentHeader /> component based on that.
Example:
const useStyles = makeStyles({
root: {
minWidth: 300,
maxWidth: 500,
margin: "10px 15px 10px 0",
},
headerTitle: {
maxWidth: 300
}
});
const CustomizedCard = () => {
const materializeUIClasses = useStyles();
return (
<Card className={materialUIClasses.root}>
<CardHeader
title={title}
// Here we can target whatever part we need: title, subtitle, action
classes={{
title: materialUIClasses.headerTitle
}}
/>
</Card>
}
this piece of code worked for me:
<CardHeader
title={
<Typography gutterBottom variant="h5" component="h2">
/* Content goes here */
</Typography>
} />
notes: package: "#material-ui/core": "^4.5.2"
I use this solution because I make use of makeStyles module.
In MUI v5, you make use of system properties in Typography by adding a fontSize prop directly in titleTypographyProps or subheaderTypographyProps:
<CardHeader
titleTypographyProps={{
fontSize: 22,
}}
subheaderTypographyProps={{
fontSize: 10,
}}
title="Shrimp and Chorizo Paella"
subheader="September 14, 2016"
/>
Live Demo

Set <Avatar> backgroundColor randomly

I have defined three backgroundColor in the style theme.
avatar: {
backgroundColor: red[500],
},
orangeAvatar: {
margin: 10,
color: '#fff',
backgroundColor: deepOrange[500],
},
purpleAvatar: {
margin: 10,
color: '#fff',
backgroundColor: deepPurple[500],
},
When ever the Avatar is loaded I would like to select one of them randomly.
<Card>
<CardHeader
avatar={
<Avatar id="av" aria-label="Recipe"
className={classes.avatar}>{this.props.userName.charAt(0).toLocaleUpperCase()}
</Avatar>}
title={this.props.userName} disableTypography={true}/>
<CardActionArea disabled={this.state.images.length == 1 ? true : false}>
<CardMedia
id={this.props.ownerId}
className={classes.media}
image={this.state.images[this.state.imageIndex]}
onClick={this.handleOnClick}
/>
</CardActionArea>
</Card>
Any advice how to do this?
Thank you
Several ways to do what you want. My suggestion: put the 3 classes in an array, pick a random number between 0 and 2 every time, and assign that class name:
<Avatar className={classes[Math.floor(Math.random() * 3)]}.../>
I was presented with the same need, perhaps this solution will also serve you, there is a function to generate the color at random and then call the function from the online style.
const useStyles = makeStyles((theme: Theme) =>
createStyles({
large: {
fontSize: "2.5rem",
width: 100,
height: 100
}
})
);
function randomColor() {
let hex = Math.floor(Math.random() * 0xFFFFFF);
let color = "#" + hex.toString(16);
return color;
}
...
return (
<Avatar
variant="square"
src={imageSrc}
alt={alt}
className={classes.large}
style={{
backgroundColor: randomColor()
}}
/>
)
ref:
Javascript random color
Avatar random backgroundColor on fallback
let classNameHolder = ["avatar","orangeAvatar","purpleAvatar"];
<Card>
<CardHeader
avatar={
<Avatar id="av" aria-label="Recipe"
className={classNameHolder[Math.floor(Math.random() * 3)]}>{this.props.userName.charAt(0).toLocaleUpperCase()}
</Avatar>}
title={this.props.userName} disableTypography={true}/>
<CardActionArea disabled={this.state.images.length == 1 ? true : false}>
<CardMedia
id={this.props.ownerId}
className={classes.media}
image={this.state.images[this.state.imageIndex]}
onClick={this.handleOnClick}
/>
</CardActionArea>
</Card>

Resources