MUI: должно быть указано свойство `image` или `src`

#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} />
)}
  

введите описание изображения здесь

Демонстрация Codesandbox

Ответ №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" 
/>