在 render 方法中使用 promise 渲染 React 组件 [英] Rendering React components with promises inside the render method

查看:69
本文介绍了在 render 方法中使用 promise 渲染 React 组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个组件,它获取一组项目作为道具,并将它们maps 到一组组件,这些组件被呈现为父组件的子组件.我们使用存储在 WebSQL 中的图像作为字节数组.在 map 函数中,我从项目中获取图像 Id 并异步调用 DAL 以获取图像的字节数组.我的问题是我无法将承诺传播到 React,因为它不是为了处理渲染中的承诺而设计的(无论如何我都不能说).我来自 C# 背景,所以我想我正在寻找类似 await 关键字的东西来重新同步分支代码.

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

var items = this.props.items.map(function (item) {var imageSrc = Utils.getImageUrlById(item.get('ImageId'));//<-- 这包含一个异步调用返回 (<MenuItem text={item.get('ItemTitle')}imageUrl={imageSrc}/>);});

getImageUrlById 方法如下所示:

getImageUrlById(imageId) {return ImageStore.getImageById(imageId).then(function (imageObject) {//<-- getImageById 返回一个promisevar completeUrl = getLocalImageUrl(imageObject.StandardConImage);返回完整网址;});}

这不起作用,但我不知道我需要修改什么才能使其起作用.我尝试向链中添加另一个承诺,但随后出现错误,因为我的渲染函数返回了一个承诺而不是合法的 JSX.我在想,也许我需要利用 React 生命周期方法之一来获取数据,但由于我需要 props 已经存在,我可以'不知道我在哪里可以做到这一点.

解决方案

render() 方法应该从 this.propsthis.state<渲染 UI/code>,所以要异步加载数据,可以使用this.state来存储imageId:imageUrl映射.

然后在您的 componentDidMount() 方法中,您可以从 imageId 填充 imageUrl.然后 render() 方法应该通过渲染 this.state 对象

变得纯粹而简单

注意this.state.imageUrls是异步填充的,所以渲染出来的图片列表项在获取到url后会一一出现.您还可以使用所有图像 ID 或索引(不带 url)初始化 this.state.imageUrls,这样您就可以在加载该图像时显示加载器.

构造函数(道具){超级(道具)this.state = {图片网址:[]};}componentDidMount() {this.props.items.map((item) => {ImageStore.getImageById(item.imageId).then(image => {const mapping = {id: item.imageId, url: image.url};const newUrls = this.state.imageUrls.slice();newUrls.push(映射);this.setState({ imageUrls: newUrls });})});}使成为() {返回 (<div>{this.state.imageUrls.map(mapping => (<div>id: {mapping.id}, url: {mapping.url}</div>))}

);}

I have a component which gets a collection of items as props and maps them to a collection of components which are rendered as children of a parent component. We use images stored in WebSQL as byte arrays. Within the map function I get an image Id from the item and make an async call to the DAL in order to get the byte array for the image. My problem is that I cannot propagate the promise in to React, since it was not designed to deal with promises in rendering (not as far as I can tell anyway). I come from a C# background, so I guess I'm looking for something like the await keyword for resync-ing branched code.

The map function looks something like this (simplified):

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

and the getImageUrlById method looks like this:

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

This doesn't work, but I don't know what I need to modify to make this work. I tried adding another promise to the chain, but then I get an error because my render function return a promise instead of legal JSX. I was thinking that maybe I need to leverage one of the React life-cycle methods to fetch the data, but since I need the props to already be there, I can't figure out where I can do this.

解决方案

render() method should render UI from this.props and this.state, so to asynchronously load data, you can use this.state to store imageId: imageUrl mapping.

Then in your componentDidMount() method, you can populate imageUrl from imageId. Then the render() method should be pure and simple by rendering the this.state object

Note that the this.state.imageUrls is populated asynchronously, so the rendered image list item will appear one by one after its url is fetched. You can also initialize the this.state.imageUrls with all image id or index (without urls), this way you can show a loader when that image is being loaded.

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

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

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

render() {
    return (
      <div>
        {this.state.imageUrls.map(mapping => (
            <div>id: {mapping.id}, url: {mapping.url}</div>
        ))}
      </div>
    );
}

这篇关于在 render 方法中使用 promise 渲染 React 组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆