web-dev-qa-db-fra.com

Rendu React composants avec promesses dans la méthode de rendu

J'ai un composant qui obtient une collection d'éléments comme accessoires et maps à une collection de composants qui sont rendus en tant qu'enfants d'un composant parent. Nous utilisons les images stockées dans WebSQL sous forme de tableaux d'octets. Dans la fonction map, j'obtiens un ID d'image de l'élément et passe un appel asynchrone au DAL afin d'obtenir le tableau d'octets de l'image. Mon problème est que je ne peux pas propager la promesse de réagir, car elle n’était pas conçue pour tenir les promesses de restitution (pas pour autant que je sache de toute façon). Je viens d'un contexte C#, je suppose donc que je recherche quelque chose comme le mot clé await pour la resynchronisation du code ramifié.

La fonction map ressemble à ceci (simplifié):

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

et la méthode getImageUrlById ressemble à ceci:

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

Cela ne fonctionne pas, mais je ne sais pas ce que je dois modifier pour que cela fonctionne. J'ai essayé d'ajouter une autre promesse à la chaîne, mais une erreur s'est produite car ma fonction de rendu renvoie une promesse au lieu de JSX légal. Je pensais que je devais peut-être utiliser l'une des méthodes du cycle de vie React pour récupérer les données, mais comme j'ai besoin du props pour y être déjà, je ne sais pas où je peux. fais ça.

62
Elad Lachmi

La méthode render() doit rendre l'interface utilisateur depuis this.props et this.state, afin de charger les données de manière asynchrone. Vous pouvez utiliser this.state pour stocker le mappage imageId:imageUrl.
Ensuite, dans votre méthode componentDidMount(), vous pouvez renseigner imageUrl à partir de imageId. Ensuite, la méthode render() devrait être pure et simple en rendant l'objet this.state

Voici un exemple de code rapide:
Notez que le this.state.imageUrls est rempli de manière asynchrone, de sorte que l'élément de liste d'images rendues apparaît un par un après l'extraction de son URL. Vous pouvez également initialiser le this.state.imageUrls avec tous les identificateurs d'image ou index (sans les URL), ainsi vous pourrez afficher un chargeur lorsque cette image est en cours de chargement.

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

Ou vous pouvez utiliser react-promise:

Installez le paquet:

npm i react-promise

Et votre code ressemblera à quelque chose comme ça:

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

Documents complets: react-promise

18
Ze Rubeus