1. ホーム
  2. javascript

[解決済み] Reactコンポーネントをrenderメソッド内でプロミスでレンダリングする

2023-06-12 10:30:49

質問

アイテムのコレクションをプロップスとして取得するコンポーネントがあります。 map を使用して、親コンポーネントの子としてレンダリングされるコンポーネントのコレクションにそれらを追加します。に格納されている画像を使用しています。 WebSQL にバイト配列として格納されている画像を使用しています。このため map 関数内で、アイテムから画像 ID を取得し、非同期呼び出しで DAL を非同期で呼び出し、画像のバイト配列を取得します。私の問題は、Reactがレンダリングで約束を扱うように設計されていないため、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 がすでに存在する必要があるため、どこでこれを行うことができるのかがわかりません。

どのように解決するのですか?

render() メソッドでUIをレンダリングする必要があります。 this.propsthis.state というように、非同期でデータを読み込むために this.state を格納するために imageId: imageUrl のマッピングになります。

そして、あなたの componentDidMount() メソッドに入力することができます。 imageUrl から imageId . 次に render() メソッドをレンダリングすることで、純粋かつシンプルになるはずです。 this.state オブジェクトをレンダリングします。

なお this.state.imageUrls は非同期に入力されるので、レンダリングされた画像リストアイテムはその url が取得された後に一つずつ表示されることに注意してください。を初期化することもできます。 this.state.imageUrls をすべての画像 ID またはインデックス (URLなし) で初期化することもでき、この場合は画像が読み込まれているときにローダーを表示することができます。

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