#reactjs #material-ui
#reactjs #материал-пользовательский интерфейс
Вопрос:
Похоже, CardMedia
что при создании компонента требуется изображение. Поскольку я извлекаю данные изображения через componentDidMount
(RestAPI), то компонент уже смонтирован.
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 >
);
}
}
Я могу переместить все API на один уровень выше, поэтому я использую props для передачи данных image, но я хотел бы знать, есть ли у вас, ребята, какое-нибудь элегантное решение.
Ответ №1:
или вы можете выполнить простую проверку в самом компоненте, чтобы избежать сброса состояния, например, отображать счетчик mui во время загрузки контента, это исправит предупреждение и отобразит приятный отзыв пользователю
<>
{imgUrl ? (
<CardMedia
component="img"
alt="Contemplative Reptile"
height="140"
src={imgUrl}
title="Contemplative Reptile"
/>
) : (
<Spinner />
)}
</>
Ответ №2:
Вы можете использовать Skeleton
компонент для отображения прямоугольного заполнителя той же высоты, что и изображение, во время его извлечения:
{loading ? (
<Skeleton sx={{ height: 140 }} animation="wave" variant="rectangular" />
) : (
<CardMedia component="img" height="140" image={YOUR_IMAGE_URL} />
)}
Ответ №3:
Я также столкнулся с такой же проблемой, я просто добавил ссылку на изображение в image
prop of <CardMedia>
.
Нравится,
<CardMedia
id={this.props.ownerId}
className={classes.media}
image={this.state.images[this.state.imageIndex] || 'https://user-images.githubusercontent.com/194400/49531010-48dad180-f8b1-11e8-8d89-1e61320e1d82.png'}
onClick={this.handleOnClick} />
Для меня это решалось простым добавлением ссылки на изображение.
Ответ №4:
Не уверен, что содержит AppData, но я внес некоторые изменения в ваш код, надеюсь, это поможет вам лучше понять.
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 amp;amp;
<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 >
);
}
}
Предложение просмотрите ваш массив AppData, возможно, хорошей идеей будет распечатать содержимое после его извлечения, давайте посмотрим пример.
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>);
Таким образом, мы ждем получения асинхронных данных перед рендерингом компонента, ранее я изменил, вместо отключения компонента просто запретите его рендеринг, если у вас все еще нет изображений.
Комментарии:
1. Здравствуйте, Альберт, и большое вам спасибо за ваш ответ. Извинился за недостаток информации. Массив AppData содержит объекты. Я создал другой массив только для ImageUrl, просто чтобы упростить код. Я подозреваю, что основная проблема заключается в том, что изображение не определено на первой итерации, и поскольку CardMedia уже смонтирована и данных нет, я получу это сообщение об ошибке.
2. Я добавил скриншот, чтобы вы могли видеть данные в AppData.
3. просматривая ваш код, я думаю, вы хотите отобразить массив карточек с полученной информацией, я собираюсь обновить ваш код, чтобы устранить ошибку другое предложение, возможно, оно работает лучше для вас.
4. Спасибо. Мне удается обойти это, используя «@material / react-card», а не «@material-ui». Ценю помощь.
Ответ №5:
Я столкнулся с той же проблемой и решил ее, инициализировав это состояние в конструкторе. У «CardMedia» есть атрибут ‘image’, который должен получать строку, но когда вы хотите отправить туда состояние, что-то вроде image={this.state.images[this.state.imageIndex]}
, оно возвращает null при первом преобразовании. Вы можете решить проблему, добавив приведенный ниже код в свой конструктор.
this.state = {
images: 'some default address/link/values'
};
Ответ №6:
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} />
))}
Предоставление реквизита изображения с прямым URL также работает!
Ответ №7:
просто добавьте component =»image», и все готово
<CardMedia component="image"/>
Ответ №8:
Чтобы получить изображение в компоненте CardMedia, следуйте приведенному ниже способу:-
Импортируйте изображение из любой папки в желаемый компонент, и это будет сделано!
import picture from "../assets/picture.jpg"
<CardMedia
component="img"
height="20%"
image={image}
alt="scene"
/>