J'ai un composant qui obtient une collection d'éléments comme accessoires et map
s à 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.
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>
);
}
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