【问题标题】:Render images from files array on client with Reactjs使用 Reactjs 从客户端上的文件数组中渲染图像
【发布时间】:2020-02-07 06:02:18
【问题描述】:

我是 React 新手,我正在实现一个多文件上传系统。我目前已经通过按钮上的单击事件处理程序实现了用户驱动的文件选择,该按钮将所选文件添加到数组中。

由于某种原因,当我选择一个文件时,控制台中会显示以下错误,导致应用程序停止工作:

Uncaught Invariant Violation:对象作为 React 子对象无效 (发现:[对象承诺])。如果你打算渲染一个集合 孩子们,用数组代替

作为参考,我的此功能界面如下所示:

以下是我的组件实现的相关部分:

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

并且这个方法是在文件onchange事件上调用的

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);
    });
};

【问题讨论】:

    标签: reactjs file file-upload


    【解决方案1】:

    目前,您的代码正试图通过调用 getDataURL() 函数映射 portfolioItems 来直接呈现 Promise 对象。目前,React 基于同步渲染,这意味着 React 目前无法实现“基于承诺的渲染”。

    要达到您的要求,请考虑在您的渲染逻辑之外(即在addPortfolio() 中)解决getDataURL() 返回的承诺。

    这需要扩展您的组件状态以保存由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>
    )}
    

    希望有帮助!

    【讨论】:

    • 所以我在用户单击添加按钮时将文件转换为 dataurl ?
    • 是的,这是正确的,您希望将 promise/async 代码转移到 click 事件处理程序中,然后使用支持渲染所需的数据更新组件状态,以便渲染不需要基于 async/promise 的函数来电
    • Src 进入图像但图像损坏
    • 我很抱歉 - 我的回答有一个小错误。请参阅更新的渲染逻辑中imageSrc 的使用。这有帮助吗?
    猜你喜欢
    • 2016-06-28
    • 2023-04-09
    • 1970-01-01
    • 2017-06-04
    • 2019-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多