问题
Its looks like CardMedia need an image while component is created. Since I am pulling the image data via componentDidMount (RestAPI) then the component is already mount.
componentDidMount() {
// get all items via category ID and owner ID
const restApi = new API({ url: 'api' })
restApi.createEntity({ name: 'items' })
// api/items/<categoryId>/<ownerId>
restApi.endpoints.items.getTwo({ id_a: this.props.categoryId, id_b: this.props.ownerId }).then(({ data }) => this.setState({ appData: data }))
}
render() {
const { classes } = this.props;
let classNameHolder = [classes.redAvatar, classes.greenAvatar, classes.blueAvatar, classes.purpleAvatar];
this.state.appData.map(element => {
this.state.images.push(element.imageUrl);
});
return (
< Card >
<CardHeader
avatar={
<Avatar aria-label="Recipe"
className={classNameHolder[Math.floor(Math.random() * classNameHolder.length)]}>
{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 >
);
}
}
I can move the all API one level up so I use the props in order to pass data image but I would like to know if you guys have any some elegant solution .
Thanks
回答1:
or you can do a simple check in the component itself so to avoid resetting the state, display a mui spinner for instance while content loads this will fix the warning and display nice feedback to the user
<>
{imgUrl ? (
<CardMedia
component="img"
alt="Contemplative Reptile"
height="140"
src={imgUrl}
title="Contemplative Reptile"
/>
) : (
<Spinner />
)}
</>
回答2:
Not sure what appData contains, but I made some changes to your code, hopefully is gonna give you a better understanding.
render() {
const { classes } = this.props;
let classNameHolder = [classes.redAvatar, classes.greenAvatar, classes.blueAvatar, classes.purpleAvatar];
/*
// you don't save the return of the next array anywhere, so this map is doing nothing.
this.state.appData.map(element => {
// you cannot redefine state like this, to redefine state you have to use setState
this.state.images.push(element.imageUrl);
});
*/
const imagesUrl = this.state.appData.map(el => el.imageUrl);
return (
< Card >
<CardHeader
avatar={
<Avatar aria-label="Recipe"
className={classNameHolder[Math.floor(Math.random() * classNameHolder.length)]}>
{this.props.userName.charAt(0).toLocaleUpperCase()}
</Avatar>}
title={this.props.userName} disableTypography={true} />
{/* This part I don't undestand much what you try to do, I can propose use map of imagesUrl. But to help you more I need to know more info about what you try to do here */}
{/* Let's not render this part of the component instead of disabled it */}
{imagesUrl.length > 0 &&
<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 >
);
}
}
Suggestion reviewing your array appData, maybe is good idea print the content after you retrieve it, let's see an example.
const { classes } = this.props;
const classNameHolder = [classes.redAvatar, classes.greenAvatar, classes.blueAvatar, classes.purpleAvatar];
const AvatarComponent = (
<Avatar aria-label="Recipe"
className={classNameHolder[Math.floor(Math.random() *
classNameHolder.length)]}>
{this.props.userName.charAt(0).toLocaleUpperCase()}
</Avatar>
);
return (<div className="Cards">
{this.state.appData.map(data => (
<Card>
<CardHeader avatar={AvatarComponent} title={this.props.userName} disableTypography={true} />
<CardActionArea disabled={data.imageUrl !== ''}>
<CardMedia
id={this.props.ownerId}
className={classes.media}
image={this.state.images[this.state.imageIndex]}
onClick={this.handleOnClick} />
</CardActionArea>
</Card>
))}
</div>);
Like this, we wait to get the async data before rendering the component, previously I changed, instead of disabling the component just prevent render it if you still don't have the images.
回答3:
I faced with the same problem and solved it by initializing that state in the constructor. The "CardMedia" has 'image' attribute which needs to receive a String, but when you want to send a state there, something like image={this.state.images[this.state.imageIndex]}
, it returns null in the first rending time. You can solve the problem by adding the below code in your constructor.
this.state = {
images: 'some default address/link/values'
};
回答4:
const photos = [
"http://i.photo.cc/300?img=1",
"http://i.photo.cc/300?img=2",
"http://i.photo.cc/300?img=3",
"http://i.photo.cc/300?img=4"
];
{photos.map(photo => (
<CardMedia image={photo} />
))}
Providing image prop with the direct URL also works!
来源:https://stackoverflow.com/questions/55290345/material-ui-either-image-or-src-property-must-be-specified