Рендеринг изображений из массива файлов на клиенте с помощью Reactjs - PullRequest
2 голосов
/ 09 октября 2019

Я новичок в React и внедряю многофайловую систему загрузки. В настоящее время реализован пользовательский выбор файлов с помощью обработчика событий нажатия на кнопку, которая добавляет выбранный файл в массив.

По какой-то причине, когда я выбираю файл, в консоли отображается следующая ошибка, из-за которой приложение перестает работать:

Неуязвимое нарушение инварианта: объекты недопустимы какReact child (найдено: [Обещание объекта]). Если вы намеревались визуализировать коллекцию дочерних элементов, используйте вместо этого массив

. Для справки мой интерфейс для этой функции выглядит следующим образом: enter image description here

ИВот соответствующие части моей реализации компонента:

state = {
  selectedPortifolio: {},
  portflioFiles: []
}

И этот метод вызывается для события onchange file

loadPortfolio = (e) => {
        if (e.target.files) {
            this.setState({
                selectedPortifolio: {
                    file: e.target.files[0],
                    filename: e.target.files[0].name
                }
            });
        }
    };

И когда нажимается кнопка добавления, вызывается этот метод.

addPortfolio = () => {
        if (
            this.state.selectedPortifolio &&
            this.state.selectedPortifolio.file
        ) {
            let items = this.state.portflioFiles;
            items.push(this.state.selectedPortifolio);
            this.setState({ selectedPortifolio: {}, portflioFiles: items });
            console.log(this.state.portflioFiles);
        }
    };

После всего этого я загружаю этот массив в div

{this.state.portflioFiles.length > 0 ? (
    this.state.portflioFiles.map((item, index) => {
        return (
            <div className="portfolio-file" key={index}>
                {getDataURL(item.file).then((data) => {
                    return (
                        <image
                            src={data}
                            alt={item.filename}
                        />
                    );
                })}
            </div>
        );
    })
) : (
    <div></fdv>
)}

И метод getDataURL определен в другом файле.

export const getDataURL = (file) => {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => resolve(reader.result);
        reader.onerror = (error) => reject(error);
    });
};

1 Ответ

1 голос
/ 09 октября 2019

В настоящее время ваш код пытается напрямую отобразить объекты обещания, сопоставив portfolioItems с помощью вызова функции getDataURL(). В настоящее время React основан на синхронном рендеринге, что означает, что «рендеринг на основе обещаний» в настоящее время невозможен с React.

Чтобы достичь того, что вам требуется, рассмотрите возможность разрешения обещаний, возвращаемых getDataURL() вне вашего рендеринга. логика (т.е. в addPortfolio()).

Для этого потребуется, чтобы состояние вашего компонента было расширено для хранения данных изображения, разрешенных обещанием, возвращаемым getDataURL(). Затем вы обновите логику рендеринга вашего компонента так, чтобы изображения, отрисованные из данных изображений, теперь присутствовали в состоянии вашего компонента:

Обновить форму состояния

state = {
  selectedPortifolio: {},
  portflioFiles: [],
  portflioImages : [] // Extend state with arrage for image data
}

Обновление addPortfolio ()

addPortfolio = () => {
        if (
            this.state.selectedPortifolio &&
            this.state.selectedPortifolio.file
        ) {
            let items = this.state.portflioFiles;
            let images = this.state.portflioImages;
            items.push(this.state.selectedPortifolio);

            // Resolve promise outside of render-logic. Once data 
            // required for rendering is available, update state
            // to trigger a re-render
            getDataURL(this.state.selectedPortifolio).then((image) => {
                this.setState({ 
                  selectedPortifolio: {}, 
                  portflioFiles: items,
                  // Add resolved image to portflioImages images array
                  portflioImages : images.concat([image]) 
            });
          });
        }
    };

Обновление логики рендеринга

{this.state.portflioImages.length > 0 ? (
    /* map portflioImages directly to image without promise */
    this.state.portflioImages.map((imageSrc, index) => {
        return (
            <div className="portfolio-file" key={index}>
                <img src={imageSrc} alt={item.filename} />
            </div>
        );
    })
) : (
    <div></fdv>
)}

Надеюсь, это поможет!

...