Rendering React components with promises inside the render method

Solution 1:

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

Solution 2:

Or you can use react-promise :

Install the package :

npm i react-promise

And your code will look something like so :

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

Edit: Oct 2019

The last build of react-promise provide a hook called usePromise:

import usePromise from 'react-promise';

const ExampleWithAsync = (props) => {
  const {value, loading} = usePromise<string>(prom)
  if (loading) return null
  return <div>{value}</div>}
}

Full docs: react-promise