ReactJS: рендеринг массива изображений - PullRequest
2 голосов
/ 13 марта 2019

Я все еще новичок в ReactJS, и в настоящее время я перебираю Spotify API, и он прекрасно работает, но я наткнулся на проблему, пытаясь отобразить массив изображений, которые были получены с помощью API. Сначала я попытался вызвать его внутри компонента render(), но он создает только список пустых «неопределенных» изображений с отображением только атрибута alt. Во-вторых, я попробовал это внутри return() и у меня просто тот же симптом, что и у первого, на этот раз без каких-либо изображений.

Эта проблема возникает, однако, только когда я пытаюсь использовать метод .map(); когда я отрисовываю изображение индивидуально, оно работает просто отлично.

import React, { Component } from "react";

let someData = "hello";

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      playlists: { name: [], plist_id: [], albumArt: [] }
    };
  }

  getPlaylists(someData) {
    let plistNames = [];
    let plistContents = [];
    let plistArts = [];

    someApi
      .searchPlaylists(someData)
      .then(data => {
        if (data.playlists.items) {
          if (data.playlists.items.length > 0) {
            console.log(data);
            data.playlists.items.forEach(plist => {
              plistNames.push(plist.name);
              plistContents.push(plist.id);
              plistArts.push(plist.images[0].url);

              this.setState({
                playlists: {
                  name: plistNames,
                  plist_id: plistContents,
                  albumArt: plistArts
                }
              });
            });
          }
        }
      })
      .catch(err => {
        console.error(err);
      });
  }

  render() {
    //Produces a list of empty images with only the alt attribute showing up
    let _playlists = this.state.playlists.albumArt.map((plist, index) => {
      return <img key={index} src={plist.albumArt} alt="Album Art"/>
    })
  return (
      <div className="App">
        <button onClick={() => this.getPlaylists(someData)}>
          Get Playlist
        </button>

      {_playlists}

      {/*  THIS PRODUCES a similar sympton as the former
          {playlists.albumArt.map((plist, index) => {
              <img key={index}  src={plist.albumArt} alt="Album Art"/>
              })
          } */}

      {/*  THIS IMAGE RENDERS THE FIRST ELEMENT FROM THE ARRAY AND WORKS FINE
            <img src={playlists.albumArt[0]}/> */}

      </div>
    );
  }
}

Как можно решить такую ​​проблему? Большое спасибо за ваше время и помощь.

Ответы [ 4 ]

1 голос
/ 14 марта 2019

Вы в настоящее время наносите на карту свой массив обложек альбомов, используя:

let _playlists = this.state.playlists.albumArt.map((plist, index) => {
  return <img key={index} src={plist.albumArt} alt="Album Art"/>
})

Проблема в том, что вы устанавливаете src ваших <img /> тегов на plist.albumArt, тогда как на самом деле значение «plist» - это URL, который вы хотите:

let _playlists = this.state.playlists.albumArt.map((plist, index) => {
  return <img key={index} src={plist} alt="Album Art"/>
})

Как уже упоминалось, не рекомендуется устанавливать состояние во время цикла. Скорее зациклите / отобразите данные и сохраните их в локальной переменной, которую вы можете использовать для вызова setState один раз.

1 голос
/ 14 марта 2019

Не могу сказать наверняка, потому что мне нужно увидеть структуру возвращаемых данных, но я уверен, что вы не хотите установить состояние в цикле forEach()куча раз.

Вместо этого вы, вероятно, хотите отобразить результаты данных и преобразовать их в некоторый полезный массив объектов, прежде чем добавлять их в состояние, чтобы вы могли отобразить их в render (что выглядит хорошо) идоступ к содержимому предсказуемо.

При этом я ожидаю, что ваш .then() блок после searchPlaylists вызова будет выглядеть примерно так:

const playlistsWrangled =  data.playlists.items.map(plist => ({ 
  name: plist.name, 
  plist_id: plist.id, 
  albumArt: plist.images[0].url 
}));

this.setState({ playlists: wrangledPlaylists });
1 голос
/ 14 марта 2019

Я полагаю, что разница между вашими двумя делами заключается в том, что в «рабочем» случае у вас нет альтернативной опоры.

Вам нужно обрезать некоторые углы, если вы хотите, чтобы изображения отображались корректно во время загрузки,Либо используйте модули, которые постепенно обрабатывают загрузку изображения для вас, либо, если вас не волнует доступность, сделайте пустой тег alt и присвойте изображению цвет фона по умолчанию (если вы хотите, вы можете установить тег alt после загрузки).

1 голос
/ 13 марта 2019

А как насчет условного встроенного оператора?Таким образом, он будет отображаться после получения информации?

    {this.state.playlist.name ?  
    //have your code here to display
    :
    <LoadingSpinner />
}
...