ホームページ >ウェブフロントエンド >CSSチュートリアル >サスペンスの反応:データの読み込み中に学んだ教訓
反応サスペンス:データの読み込みから学んだ教訓
Suspenseは、データロードなどの非同期操作を調整するのに役立つReactの今後の機能であり、UIの状態の不一致を防ぐことができます。これが正確に何を意味するのかをより詳細に説明し、サスペンスの簡単な紹介、より現実的なユースケース、いくつかの教訓を学んだことを説明します。
私が導入した機能はまだアルファ段階にあり、生産環境では使用してはなりません。この投稿は、今後の機能を最初に見て、彼らが将来に向かう場所を理解したい人向けです。
アプリケーション開発の最も困難な部分の1つは、アプリケーションの状態とデータのロード方法を調整することです。状態の変更は、通常、複数の場所で新しいデータの読み込みをトリガーします。通常、各データには、おおよそデータがアプリケーション内の場所にある独自のロードUI(「回転子」など)があります。データ読み込みの非同期性は、これらの要求を任意の順序で返すことができることを意味します。その結果、多くの異なるスピナーでアプリケーションが表示され、消えるだけでなく、さらに悪いことに、アプリケーションは一貫性のないデータを表示する可能性があります。 3つのデータロードのうち2つが完了した場合、3番目のポジションの上部にロードスピナーが表示されますが、現在は古い古いデータが表示されます。
私はそれが多すぎることを知っています。あなたがそれを混乱させていると思うなら、あなたは私が書いたサスペンスに関する以前の記事に興味があるかもしれません。この記事では、サスペンスとは何か、それが実施するものをさらに詳しく紹介します。これらの小さな詳細のいくつかは現在時代遅れであることに注意してください。つまり、 useTransition
フックはtimeoutMs
値を受け入れなくなりますが、無期限に待機します。
それでは、詳細を簡単に見てから、潜んでいるトラップで特定のユースケースに進みましょう。
幸いなことに、Reactチームは、データをロードするためだけにこれらの努力を制限しないほど賢いです。サスペンスは、低レベルのプリミティブを介して機能し、ほとんどすべてに適用できます。これらのプリミティブを簡単に見てみましょう。
初めに<suspense></suspense>
境界、それはfallback
属性を受け入れます:
<suspense fallback="{<Fallback"></suspense> }>
このコンポーネントの下の子コンポーネントがハングするたびに、それはfallback
になります。何人のサブコンポーネントが停止されていても、何らかの理由でfallback
が表示されます。これは1つの方法であり、UIが一貫していることを保証します。すべてが準備が整うまで何もレンダリングしません。
しかし、コンテンツが最初にレンダリングされた後にユーザーがステータスを変更して新しいデータをロードするとどうなりますか?私たちは確かに、既存のUIが消滅し、それが悪いユーザーエクスペリエンスになることを望んでいませんfallback
代わりに、新しいUIが表示される前にすべてのデータが準備されるまで、ロードスピナーを表示することをお勧めします。
useTransition
フックはこれを実装します。このフックは、関数とブール値を返します。関数を呼び出し、状態の変更を包みます。今、物事は面白くなっています。 Reactはステータスの変更を適用しようとします。何かがぶら下がっている場合、Reactはブール値をtrue
に設定し、ハングが終了するのを待ちます。完了すると、ステータスの変更を再度適用しようとします。たぶんそれは今回成功するでしょう、あるいは何か他のものがぶら下がっているかもしれません。とにかく、ブールフラグはすべてが準備が整うまでtrue
ままであり、その後、状態の変更は完了し、UIに反映されます。
最後に、どのように吊るしますか?私たちは約束を投げてぶら下がっています。データが要求され、フェッチする必要がある場合は、フェッチし、そのフェッチに関連する約束を投げます。この低レベルのサスペンドメカニズムは、あらゆるものに使用できることを意味します。怠zyなロードコンポーネントのReact.lazy
ユーティリティはすでにサスペンスで動作します。サスペンスを使用する前に、コンテンツが移動するのを防ぐためにUIを表示する前に画像がロードされるのを待つ前に書きました。
心配しないでください、これらすべてについて説明します。
他の同様の記事の例とはわずかに異なるものを作成します。サスペンスはまだアルファフェーズにあるため、お気に入りのロードデータユーティリティにはまだサスペンスサポートがない可能性があることを忘れないでください。しかし、それは私たちが何かを偽造できず、サスペンスがどのように機能するかを理解することができないという意味ではありません。
いくつかのデータを表示し、サスペンスに基づいていくつかのプリロードされた画像を組み合わせた無限のロードリストを作成しましょう。データと、より多くのデータをロードするボタンを表示します。データがレンダリングされると、関連する画像をプリロードし、準備が整う前にハングします。
このユースケースは、私が私のサイドプロジェクトで行った実際の作業に基づいています(繰り返しますが、生産でサスペンスを使用しないでくださいが、サイドプロジェクトは許可されています)。私は当時自分のGraphQLクライアントを使用していましたが、この投稿の動機は私が抱えていた困難のいくつかでした。操作を簡素化し、単一のデータ読み込みユーティリティではなく、サスペンス自体に集中するために、データの読み込みを断続するだけです。
これは、最初に試したサンドボックスです。すべてを段階的に説明するためにそれを使用しますので、今すぐすべてのコードを理解するために急ぐ必要はありません。
ルートApp
コンポーネントは、次のようなサスペンス境界をレンダリングします。
<suspense fallback="{<Fallback"></suspense> }>
fallback
、何かがぶら下がっているときはいつでもレンダリングします( useTransition
Callで状態の変更が発生しない限り)。物事を理解しやすくするために、このFallback
コンポーネントはUIピンク全体を回しました。
DataList
コンポーネント内に現在のデータブロックをロードしています。
const newdata = usequery(param);
useQuery
フックは、シミュレートされたネットワークリクエストのタイムアウトを含む偽のデータを返すためにハードコードされています。データがキャッシュされていない場合、キャッシュされた結果を処理し、約束を投げます。
表示しているメインデータリストにステータスを保存します(少なくとも今のところ)
const [data、setData] = uesestate([]);
フックから新しいデータが渡されたら、メインリストに追加します。
effect(()=> { setdata((d)=> d.concat(newData)); }、[newData]);
最後に、ユーザーがより多くのデータを必要とするとき、彼らはこの関数を呼び出すボタンをクリックします。
関数loadmore(){ starttransition(()=> { SetParam((x)=> x 1); }); }
最後に、 SuspenseImg
コンポーネントを使用して、各データで表示している画像のプリロードを処理することに注意してください。ランダムな画像は5つだけ表示されますが、クエリ文字列を追加して、遭遇する新しいデータごとに新しい負荷が作成されるようにしました。
現在の場所を要約するために、現在のデータをロードするフックがあります。このフックは、サスペンスメカニズムに従い、読み込みが発生したときに約束を投げます。そのデータが変更されるたびに、実行中のプロジェクトの合計リストが更新され、新しいプロジェクトが添付されます。これはuseEffect
で発生します。各プロジェクトは画像をレンダリングし、 SuspenseImg
コンポーネントを使用して画像をプリロードし、準備が整う前にハングします。一部のコードがどのように機能するかに興味がある場合は、サスペンスで画像をプリロードする以前の投稿をご覧ください。
すべてが正常に機能している場合、これは非常に退屈なブログ投稿になります、心配しないでください、それは普通ではありません。ピンクのfallback
画面が表示され、初期負荷ですぐに隠されますが、再表示することに注意してください。
ボタンをクリックしてより多くのデータをロードすると、インラインロードインジケーター( useTransition
フックで制御)がtrue
に反転します。次に、 false
に反転し、元のピンクのfallback
が表示されます。ピンクの画面は、最初の負荷の後に表示されなくなると予想されます。どうしたの?
それは目立つ場所に隠されています:
effect(()=> { setdata((d)=> d.concat(newData)); }、[newData]);
useEffect
、状態の変更が完了したときに実行されます。つまり、状態の変更が絞首刑にされ、DOMに適用されます。ここでは、「完了して保留中」が重要です。必要に応じてここに状態を設定できますが、その状態の変化が再びぶら下がっている場合、それはまったく新しいハングです。これが、最初の負荷とその後のデータロード後にピンクが点滅するのを見る理由です。どちらの場合も、データの読み込みが実行され、その後、状態を1つの効果に設定します。これにより、画像がプリロードされるため、新しいデータが実際にレンダリングされ、再びハングします。
それでは、この問題をどのように解決しますか?あるレベルでは、解決策は簡単です。効果に状態を設定するのを停止します。しかし、これは言うよりも簡単です。効果を使用せずに新しい結果を添付するために、実行中のエントリのリストを更新するにはどうすればよいですか? Refを使用して物事を追跡できると思うかもしれません。
残念ながら、Suspenseは参考文献に関するいくつかの新しいルールをもたらします。つまり、レンダリング内で参照を設定することはできません。なぜ疑問に思っているのであれば、サスペンスはレンダリングを実行しようとし、約束が投げられているのを見て、そのレンダリングを途中で破棄することであることを忘れないでください。レンダリングがキャンセルされ、破棄される前にrefを変更すると、refにはまだその変更がありますが、無効な値があります。レンダリング関数は純粋である必要があり、副作用はありません。これは常にReactのルールでしたが、今ではより重要です。
これが解決策です。段落で段落を説明します。
まず、メインデータリストを州に保存する代わりに、違うことをしてください。表示しているページのリストを保存しましょう。最新のページをREFに保存し(レンダリングに記述することはありません)、現在ロードされているすべてのページの配列を州に保存できます。
const currentPage = useref(0); const [pages、setPages] = uesestate([currentPage.Current]);
より多くのデータをロードするには、それに応じて更新します。
関数loadmore(){ starttransition(()=> { currentPage.current = currentPage.current 1; setPages((pages)=> pages.concat(currentPage.Current)); }); }
ただし、トリッキーな部分は、これらのページ番号を実際のデータに変換する方法です。私たちができないことは、これらのページをループして、 useQuery
フックを呼び出すことです。新しい非フックベースのデータAPIが必要です。私が過去のサスペンスデモで見た非常に非公式の大会によると、私はこの方法read()
と命名しました。フックではありません。データがキャッシュされている場合、要求されたデータを返します。そうしないと、約束がスローされます。偽のデータロードフックについては、実際の変更を行う必要はありませんでした。しかし、実際のデータロードユーティリティライブラリの場合、著者がパブリックAPIの一部として両方のオプションを公開するには、ある程度の作業が必要になる場合があります。前述のGraphQLクライアントには、実際には、クライアントオブジェクトにuseSuspenseQuery
フックとread()
メソッドの両方があります。
この新しいread()
メソッドを使用すると、コードの最後の部分は些細なものです。
const data = pages.flatmap((page)=> read(page));
各ページを取得し、 read()
メソッドを使用して対応するデータをリクエストします。いずれかのページがキャッシュされていない場合(実際にはリストの最後のページにすぎないはずです)、約束が投げられ、反応が私たちにかかっています。 Promise Parsesの場合、Reactは以前の状態変更を再度試み、このコードは再び実行されます。
flatMap
に電話をかけさせないでください。それは、新しい配列ですべての結果を取得し、それ自体が配列である場合に「フラット化」することを除いて、 map
とまったく同じことです。
これらの変更により、開始すると、すべてが期待どおりに機能します。ピンクの読み込み画面は、初期負荷時に1回表示され、その後のロードでは、すべてが準備が整うまでインラインロードステータスが表示されます。
サスペンスは、Reactのエキサイティングな更新です。それはまだアルファフェーズにあるので、重要なものに使用しようとしないでください。ただし、あなたが最初のコンテンツを体験するのが好きな開発者のようなものである場合、この投稿が公開されたときに役立つ便利な背景と情報を提供することを願っています。
以上がサスペンスの反応:データの読み込み中に学んだ教訓の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。