Open ShotaroHirose59 opened 8 months ago
ストリーミングは、ルートをより小さな「チャンク」に分割し、準備が整ったらサーバーからクライアントに段階的にストリーミングできるデータ転送技術です。
ストリーミングすることで、遅いデータ要求によってページ全体がブロックされるのを防ぐことができます。これにより、ユーザーは、UI がユーザーに表示される前にすべてのデータが読み込まれるのを待たずに、ページの一部を表示して操作できるようになります。
ユーザーはページ全体が準備されるのを待たずに、アプリを利用することができる
言葉としての意味は大きな塊
各コンポーネントはチャンクとみなすことができる。
なので、ストリーミングReactコンポーネントと上手く連携する
生成されたそれぞれの HTML には、そのページの生成に最低限必要な JavaScript コードが関連事項づけられています。 ページがブラウザから読み込まれると、JavaScript コードが走りページをインタラクティブなものにします。(この処理はハイドレーションと呼ばれています。) プリレンダリング
以下のコンポーネントを表示するとする。
import { useState } from "react";
function Hello() {
const [count, setCount] = useState(0);
return (
<>
<div>{count}</div>
<button onClick={() => setCount(() => count + 1)}>click here!</button>
</>
);
}
export default Hello;
Next.jsではコンポーネントをプリレンダリング(事前にサーバーでHTMLを生成)する。 ブラウザ側でハイドレーションが実行され、onClickイベントが動作するようになります。
ちなみに、Reactの場合は以下のようになる。
<div id="root"></div>
空のdivの要素内にコンポーネント等の要素がクライアント側で追加されていく流れになる。
loading.tsxではページ全体をストリーミングする。(layout.tsxはストリーミングしない)
loading.tsxを実行すると以下のようなことが起こる
A loading skeleton is a simplified version of the UI Many websites use them as a placeholder (or fallback) to indicate to users that the content is loading.
スケルトンはUI・UX的にとても良いと思うので、取り入れて行きたいなー。 ただ実装コストはかけたくない。
実装中のこのアプリではTailwindで簡単なコードのみでスケルトンのアニメーションが実装されてる
const shimmer =
'before:absolute before:inset-0 before:-translate-x-full before:animate-[shimmer_2s_infinite] before:bg-gradient-to-r before:from-transparent before:via-white/60 before:to-transparent';
コンポーネントは自作する必要がある。
export default function DashboardSkeleton() {
return (
<>
<div
className={`${shimmer} relative mb-4 h-8 w-36 overflow-hidden rounded-md bg-gray-100`}
/>
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
<CardSkeleton />
<CardSkeleton />
<CardSkeleton />
<CardSkeleton />
</div>
<div className="mt-6 grid grid-cols-1 gap-6 md:grid-cols-4 lg:grid-cols-8">
<RevenueChartSkeleton />
<LatestInvoicesSkeleton />
</div>
</>
);
}
Mantineでも簡単にできるっぽい https://mantine.dev/core/skeleton/
アニメーションの動きを調整したい場合はTailwindの方がやりやすそう
loading.tsxは下位のルートにも影響を与える。invoices/page.tsxとcustomers/page.tsx。 これをこれはルートグループで変更できる。
これで、loading.tsxファイルはダッシュボードの概要ページにのみ適用される。ルートグループを使用すると、URL パス構造に影響を与えることなく、ファイルを論理グループに編成できる
React Suspense を使用すると、より詳細に特定のコンポーネントをストリーミングできる。
サスペンスを使用すると、何らかの条件が満たされるまで (データがロードされるなど)、アプリケーションのレンダリング部分を延期できます。動的コンポーネントをサスペンスでラップできます。次に、動的コンポーネントのロード中に表示するフォールバック コンポーネントを渡します。
この場合、下位のコンポーネントでデータフェッチして、親のコンポーネントで下位のコンポーネントをSuspenseでラップする。
複数のコンポーネントを同時にロードしたい場合はコンポーネントをグループ化する。
ex:
export default async function CardWrapper() {
const {
numberOfInvoices,
numberOfCustomers,
totalPaidInvoices,
totalPendingInvoices,
} = await fetchCardData();
return (
<>
<Card title="Collected" value={totalPaidInvoices} type="collected" />
<Card title="Pending" value={totalPendingInvoices} type="pending" />
<Card title="Total Invoices" value={numberOfInvoices} type="invoices" />
<Card
title="Total Customers"
value={numberOfCustomers}
type="customers"
/>
</>
);
}
CardWrapper
コンポーネントを親のコンポーネントでSuspenseでラップする
サスペンスの境界をどこに置くかは以下の要素によって判断される
以下のような実装パターンがある。
サスペンス境界をどこに置くかは、アプリケーションによって異なります。一般に、データのフェッチを必要なコンポーネントまで移動し、それらのコンポーネントを Suspense でラップすることをお勧めします。ただし、アプリケーションが必要とする場合は、セクションまたはページ全体をストリーミングしても問題はありません。
一般に、データのフェッチを必要なコンポーネントまで移動
ダッシュボードのように複数データを扱うパターンでもそうだし、 TODOリストのみを扱うようなページでもこうすべきな印象。
こうするとApp Router パターンではpage.tsxを親とする下位のコンポーネントもサーバーコンポーネントであると思うが、 コンポーネントファイルをどこに置くべきなのか悩ましいところ
In the previous chapter, you made your dashboard page dynamic, however, we discussed how the slow data fetches can impact the performance of your application. Let's look at how you can improve the user experience when there are slow data requests. https://nextjs.org/learn/dashboard-app/streaming
Topics
key word
ストリーミングという言葉に対してまだあまり理解できていないかも。 内容はわかるんだろうけど。
loading skeletons、これ案件のPRに単語として出てきたな。