テーブルに表示するためにリモート リソースに対して 200 件の呼び出しを実行しようとしています。同時に、残りの呼び出し数を示す進行状況バーを表示します。
この例を使用して、Fetch()
と Promise.all()
を使用して setState()< を呼び出す方法を示します。 /code> 新しいデータを更新します。
私の問題は、各 Promise の .then()
にあり、これは何らかのロジックを計算し、setState()
を呼び出してデータを更新します。
私の進行状況バーは、Object.keys(data).length
を使用して進行状況を表示します。
Promise.all()
が「Complete」状態をトリガーし、進行状況バーが削除された後も、Promise 自体はまだ then()
を呼び出しています。これにより、解決されたすべての Promise が表示される前に進行状況バーが非表示になります。
この問題に正しく対処するにはどうすればよいですか?
デモでは、setTimeout()
を使用して、高価なロジックをシミュレートします。
問題は、Promise.all.then: 20
が Render 20
の後にある必要があることです。
レンダリング 0 ... レンダリング 12 Promise.all.then: 20 # 各レンダリング後にこれを記録する必要があります レンダリング 13 ... レンダリング 19 レンダリング 20
デモで問題を示すために、進行状況バーが完全に埋まる前に削除されました (赤色に変わりました)。
const { useState } = React; const 例 = () => { const [done, setDone] = useState(false); const [データ, setData] = useState({}); const demoData = Array.from(Array(20).keys()); const demoResolver = (x) =>新しい Promise(res => setTimeout(() => res(x), Math.random() * 1250)) constloadData = () => { const Promise = DemonData.map(c =>demoResolver(c)); Promise.forEach(promise => { 約束 .then(r => { setTimeout(() => { setData(p => ({ ...p, [r]: r })); }, 500); }) }); Promise.all(約束) .then(r => { console.log('Promise.all.then: ', r.length) setDone(true); }) } console.log('Render', Object.keys(data).length); const progressBarIsShownDebugColor = (完了) ? 「危険です」 : '情報です'; 戻る ( <セクションクラス名='セクション'>{'例'}
<進捗状況 max="{demoData.length}" 値="{オブジェクト.キー(データ).長さ}" className="{'progress" my-3 ' progressBarIsShownDebugColor}>進捗状況> セクション> ) } ReactDOM.render(, document.getElementById("react"));
.as-console-wrapper { max-height: 50px !重要; }
<リンク rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
上記のコードに示されている問題は、データを取得した後、状態を設定するまでにさらに 500 ミリ秒の非同期遅延が発生することです。実際のコードでは、
.all
の後にsetData
を呼び出す追加の処理 (おそらく同期) があるように見えます。ベスト プラクティスは、
リーリーdone
を個別の状態ではなく計算プロパティとして持つことです。その時点では、競合を設定するために状態に依存する必要がなく、Object .keys( data).length
は十分に安価であるため、パフォーマンスに悪影響を与えることはありません (また、他の領域でも使用できます。問題になった場合は、変数にキャッシュできます)。