У меня есть компонент, который получает набор объектов как опоры и map
s их к набору компонентов, которые представляются как дети родительского компонента. Мы используем изображения, сохраненные в WebSQL
как массивы байтов. В map
функция я получаю идентификатор изображения от объекта и выполняю асинхронный вызов к DAL
для получения массива байтов для изображения. Моя проблема состоит в том, что я не могу распространить обещание в Реагировать, так как оно не было разработано для контакта с обещаниями в рендеринге (не насколько я могу сказать так или иначе). Я происхожу из a 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} />
);
});
и getImageUrlById
метод похож на это:
getImageUrlById(imageId) {
return ImageStore.getImageById(imageId).then(function (imageObject) { //<-- getImageById returns a promise
var completeUrl = getLocalImageUrl(imageObject.StandardConImage);
return completeUrl;
});
}
Это не работает, но я не знаю то, что я должен изменить для создания этой работы. Я пытался добавить другое обещание цепочке, но затем я получаю ошибку, потому что моя функция рендеринга возвращает обещание вместо легального JSX. Я думал, что, возможно, должен усилить один из React
методы жизненного цикла для выборки данных, но так как мне нужно props
чтобы уже быть там, я не могу выяснить, где я могу сделать это.
render()
метод должен представить UI от this.props и this.state, так к асинхронным данным загрузки, можно использовать this.state
для хранения imageId:imageUrl
отображение.
Затем в Вашем componentDidMount()
метод, можно заполнить imageUrl от imageId. Затем render()
метод должен быть чистым и простым путем рендеринга this.state
, объект
Вот является быстрым примером кода:
Примечание, которое эти this.state.imageUrls
заполняется асинхронно, таким образом, представленный объект списка изображений появится один за другим после того, как его URL выбирается. Можно также инициализировать this.state.imageUrls
со всем идентификатором изображения или индексом (без 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>
);
}
Или можно использовать реагировать-обещание:
Установка пакет:
npm i react-promise
И Ваш код посмотрит что-то как так:
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}/>} />
);
});
Редактирование: октябрь 2019
последняя сборка реагировать-обещания обеспечивает рычаг, названный usePomise
:
import usePromise from 'react-promise';
const ExampleWithAsync = (props) => {
const {value, loading} = usePromise<string>(prom)
if (loading) return null
return <div>{value}</div>}
}
Полные документы: реагировать-обещание