Share
Embed
Transcript
57 slides
-
App Router時代のデータ 取得アーキテクチャ 2023-08-02 What's "Next" JS Meetup 基調講演 uhyo
(株式会社バベル プリンシパルエンジニア) -
App Routerって何だっけ? Next.js 13で追加された、新しいルーターの実装。 従来のPages Routerと対比してApp Routerと 呼ばれる 特徴: •
React Server Components (RSC) の上に作られている • Pages Routerには無いさまざまな機能 -
レンダリング SSR機能 サーバー クライアント リクエストURL switch文的な何か HTML文字列 DOM バンドルされた JavaScript
ハイドレーション クライアント側ナビゲーションのときも追加のバンドルを取得したりする動きがあるが省略。 以降もナビゲーションの話は特筆すべき事情がない限り省略します レンダリング -
SSR + データフェッチング サーバー クライアント リクエストURL switch文的な何か バンドルされた JavaScript データフェッチング
レンダリング HTML文字列 DOM ハイドレーション レンダリング getServerSidePropsとか -
React 18の事情 Suspenseのサポートにより、SSR時も非同期的な レンダリングが可能になった(Streaming対応SSR) • SSRの最中にサスペンドしたら待ってくれて、サスペンド解消したら追 加のコンテンツを出力してくれる • レンダリングの最中にデータフェッチングを行えるように •
アーキテクチャ的には、Suspenseの導入によりステートに頼らずに ローディング中を表現できるようになったことが大きい (SSR中にステートを変化させるのは無理なので) -
レンダリング Streaming SSR + データフェッチング サーバー クライアント リクエストURL switch文的な何か バンドルされた
JavaScript データフェッチング HTML文字列 DOM ハイドレーション レンダリング データフェッチング -
レンダリング Streaming SSR + データフェッチング サーバー リクエストURL switch文的な何か バンドルされた JavaScript
データフェッチング HTML文字列 DOM ハイドレーション レンダリング データフェッチング Suspense対応により、データ フェッチングがレンダリングの 一部になった。 -
レンダリング Streaming SSR + データフェッチング サーバー リクエストURL switch文的な何か バンドルされた JavaScript
データフェッチング HTML文字列 DOM ハイドレーション レンダリング データフェッチング SSRではサーバーとクライアン トで同じものをレンダリングす るので、データフェッチングの ロジックも両側に必要になった -
レンダリング Streaming SSR + データフェッチング サーバー リクエストURL switch文的な何か バンドルされた JavaScript
データフェッチング HTML文字列 DOM ハイドレーション レンダリング データフェッチング リクエストの重複排除などを考 えるとめちゃくちゃ面倒。 Streaming SSRだけに頼る のはきつい キャッシュを 渡す? -
RSCって何だっけ? React Server Components (RSC) では、 サーバー側コンポーネントとクライアント側コンポーネ ントという概念が導入される。 Reactアプリケーション全体で見れば、サーバー側で実 行される部分とクライアント側で実行される部分に分割
されている。 宣伝: 一言で理解するReact Server Components -
レンダリング RSCのレンダリング ※ SSRしない場合の例です サーバー クライアント DOM Reactアプリケーション サーバー側 +
クライアント側 レンダリング Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript -
レンダリング RSCのレンダリング ※ SSRしない場合の例です サーバー DOM Reactアプリケーション サーバー側 + クライアント側
レンダリング Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript 2ヶ所のレンダリングで、それ ぞれサーバー側コンポーネント とクライアント側コンポーネン トのレンダリングを行う。 -
レンダリング (サーバー側) RSC + SSR サーバー クライアント DOM Reactアプリケーション サーバー側
+ クライアント側 Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション -
レンダリング (サーバー側) RSC + SSR サーバー DOM Reactアプリケーション サーバー側 +
クライアント側 Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション ここがSSR要素 (本来クライアント側で行うレ ンダリングをサーバー側でも行 う) -
サーバー クライアント レンダリング(サーバー側) RSC + SSR DOM Reactアプリケーション サーバー側 +
クライアント側 Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション データフェッチング -
昔のNext.jsとの比較 昔のNext.js RSC(サーバー側) リクエスト データフェッチング レンダリング HTML文字列 getServerSidePropsとか レンダリング(サーバー側) レンダリング
(クライアント側) HTML文字列 データフェッチング リクエスト -
昔のNext.jsとの比較 昔のNext.js リクエスト データフェッチング レンダリング HTML文字列 getServerSidePropsとか レンダリング(サーバー側) レンダリング (クライアント側)
HTML文字列 データフェッチング リクエスト RSCの導入により、Next.jsの独 自概念が要らなくなった -
昔のNext.jsとの比較 Q. RSCでは、なぜデータフェッチングがReactアプリの 外からReactアプリの中に移動したのか? A. データフェッチングの方法の標準化のため 昔のgetServerSideProps等はReact外の概念だったが、 新しいAPI (headers()とか)はRSCの上に作られている。 フレームワーク独自の機構が減り、フレームワーク間での共通化が進んだ。
(Reactが定める“標準”に合わせた機構となった) (RSCを受け入れないフレームワークは別) -
サーバー クライアント レンダリング(サーバー側) RSC + SSR(再掲) DOM Reactアプリケーション サーバー側 +
クライアント側 Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション データフェッチング -
サーバー クライアント レンダリング(サーバー側) RSC + SSR(再掲) DOM Reactアプリケーション サーバー側 +
クライアント側 Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション データフェッチング RSCによるサーバー・クライア ント連携部分 -
サーバー クライアント レンダリング(サーバー側) DOM Reactアプリケーション サーバー側 + クライアント側 Reactアプリケーション ただのHTML
+ クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション データフェッチング サーバー側データフェッチング クライアント側データ フェッチングを発火 -
サーバー クライアント レンダリング(サーバー側) DOM Reactアプリケーション サーバー側 + クライアント側 Reactアプリケーション ただのHTML
+ クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション データフェッチング ポイント: ここで データフェッチング をしない -
Fetch on render でいいのか? Fetch on renderは、コンポーネントがレンダリング されたらそのコンポーネントが必要とするデータの取得 が始まることを指す。 レンダリング
→ fetch → レンダリング → 次のfetch ……という流れで通信を直列化させる問題がある。 -
Fetch on render でいいのか? サーバーサイドでは、fetchにかかる時間が短いことが多 い。(Next.jsサーバーとDBが同じデータセンターにあ る場合など) この場合、サーバー側コンポーネントはFetch on renderでも問題ないと考えられる。
(少なくとも、パフォーマンスボトルネックが他の場所に移る可能性は高そう) -
テストに対する考え方2案 • 普通にSCをレンダリングしてテストする。 • 今はまだできないが、そのうちできるようになる cf. https://github.com/testing-library/react-testing-library/issues/1209 • コンポーネントそのものではなく、ロジックを関数に 抜き出してテストする。
• レンダリングされるHTMLをユニットテストする必要がない場合も多 く、ロジックをフックに抜き出してテストすれば十分だったりする。 • SCではフックですらなくただのasync関数として抜き出せるので、 むしろテストしやすいかも -
RSCと状態管理の懸念 問題: SCがフェッチした状態に関してsource of truthが React内にあるので、一部の状態管理アーキテクチャと の相性が微妙 • ReduxとかRecoil型アーキテクチャでは状態管理をReactコン ポーネントから分離しているので、Reactの中→外
という微 妙なデータの流れが必要になる。 ※Recoilでは正確にはRecoilRootの中にあるが、アーキテクチャ的な話