使用render方法内的promises渲染React组件

Ela*_*hmi 63 javascript q reactjs

我有一个组件,它将一个项目集合作为道具,map并将它们转换为一组组件,这些组件呈现为父组件的子组件.我们使用WebSQL以字节数组形式存储的图像.在map函数中,我从项目中获取图像Id,并对其进行异步调用,DAL以获取图像的字节数组.我的问题是我无法将承诺传播到React,因为它不是为了处理渲染中的承诺而设计的(不管怎样我都不知道).我来自一个C#背景,所以我想我正在寻找像重新await同步分支代码的关键字.

map函数看起来像这样(简化):

var items = this.props.items.map(function (item) {
        var imageSrc = Utils.getImageUrlById(item.get('ImageId')); // <-- this contains an async call
        return (
            <MenuItem text={item.get('ItemTitle')}
                      imageUrl={imageSrc} />
       );
    });
Run Code Online (Sandbox Code Playgroud)

这个getImageUrlById方法看起来像这样:

getImageUrlById(imageId) {
    return ImageStore.getImageById(imageId).then(function (imageObject) { //<-- getImageById returns a promise
       var completeUrl = getLocalImageUrl(imageObject.StandardConImage);
       return completeUrl;
    });
}
Run Code Online (Sandbox Code Playgroud)

这不起作用,但我不知道我需要修改什么来使这项工作.我尝试向链添加另一个promise,但后来我得到一个错误,因为我的render函数返回一个promise而不是合法的JSX.我在想,也许我需要利用其中一种React生命周期方法来获取数据,但由于我需要props已经存在,我无法弄清楚我能在哪里做到这一点.

Win*_*int 79

render()方法应该从this.props和this.state呈现UI,因此要异步加载数据,您可以使用this.state存储imageId:imageUrl映射.
然后在您的componentDidMount()方法中,您可以从imageId填充imageUrl.然后render()通过渲染this.state对象, 该方法应该是纯粹和简单的

下面是一个快速示例代码:
请注意,它this.state.imageUrls是异步填充的,因此渲染的图像列表项将在获取其url后逐个显示.您还可以this.state.imageUrls使用所有图像ID或索引(不使用URL)初始化,这样您就可以在加载图像时显示加载程序.

constructor(props) {
    super(props)
    this.state = {
        imageUrls: []
    };
}

componentDidMount() {
    var self = this;
    this.props.items.map((item) => {
        ImageStore.getImageById(item.imageId).then(image => {
            var mapping = {id: item.imageId, url: image.url};
            var newUrls = self.state.imageUrls.slice();
            newUrls.push(mapping);

            self.setState({
                imageUrls: newUrls
            });
        })
    });
}

render() {
    return (<div>
        this.state.imageUrls.forEach(mapping => {
            <div>id: {mapping.id}, url: {mapping.url}`</div>
        })
        </div>
    );
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!这就是诀窍.我唯一要改变的地方(至少我用)是在`componentWillMount`而不是`componentDidMount`中执行此操作,以便没有初始的"空"渲染.`componentWillMount`在初始渲染之前运行. (4认同)
  • @Wint这行有一个错误:`var newUrls = self.state.imageUrls.slice()。push(mapping)`,因为返回的值不是数组的浅表副本,而是新数组的长度。参见[Array.prototype.push()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/push#Syntax) (2认同)

Ze *_*eus 20

或者你可以使用react-promise:

安装包:

npm i react-promise
Run Code Online (Sandbox Code Playgroud)

你的代码看起来像这样:

import Async from 'react-promise'

var items = this.props.items.map(function (item) {
    var imageSrc = Utils.getImageUrlById(item.get('ImageId')); // <-- this contains an async call
    return (
        <Async promise={imageSrc} then={(val) => <MenuItem text={item.get('ItemTitle')} imageUrl={val}/>} />    
    );
});
Run Code Online (Sandbox Code Playgroud)

完整文档:https://github.com/capaj/react-promise