web-dev-qa-db-ja.com

renderメソッド内でのReactコンポーネントのPromiseのレンダリング

アイテムのコレクションを小道具として取得し、それらを親コンポーネントの子としてレンダリングされるコンポーネントのコレクションにmapsするコンポーネントがあります。 WebSQLに格納されている画像をバイト配列として使用します。 map関数内で、アイテムから画像IDを取得し、DALへの非同期呼び出しを行って、画像のバイト配列を取得します。私の問題は、レンダリングのプロミスを処理するように設計されていないため、プロミスをReactに伝達できないことです(とにかく伝えることができる限りではありません)。私は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ライフサイクルメソッドの1つを利用してデータを取得する必要があるかもしれないと考えていましたが、propsが既に存在する必要があるため、どこでできるかわかりません。これを行う。

62
Elad Lachmi

render()メソッドはthis.propsとthis.stateからUIをレンダリングする必要があるため、データを非同期にロードするには、this.stateを使用してimageId:imageUrlマッピングを保存できます。
その後、componentDidMount()メソッドで、imageIdからimageUrlを設定できます。 render()メソッドは、this.stateオブジェクトをレンダリングすることにより、純粋でシンプルなものでなければなりません。

簡単なサンプルコードを次に示します。
this.state.imageUrlsは非同期に設定されるため、URLが取得された後、レンダリングされた画像リストアイテムが1つずつ表示されることに注意してください。 this.state.imageUrlsをすべての画像IDまたはインデックス(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>
    );
}
78
Wint

または、react-promiseを使用できます。

パッケージをインストールします。

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

完全なドキュメント: react-promise

18
Ze Rubeus