Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
App Router時代のデータ取得アーキテクチャ
Search
uhyo
August 02, 2023
Programming
50
16k
App Router時代のデータ取得アーキテクチャ
2023-08-02 What's "Next" JS Meetup
uhyo
August 02, 2023
Tweet
Share
More Decks by uhyo
See All by uhyo
React 19 + Jotaiを試して気づいた注意点
uhyo
8
2.2k
TypeScriptの次なる大進化なるか!? 条件型を返り値とする関数の型推論
uhyo
3
2k
tsconfig.jsonの最近の新機能 ファイルパス編
uhyo
7
2.6k
非同期処理を活用しながらRust製wasmとJSを連携する方法(wasm-bindgenを使いたくない人向け)
uhyo
4
3.8k
tsconfig.jsonの設定を見直そう!フロントエンド向け 2024夏
uhyo
26
9.3k
React 19を概念から理解する
uhyo
22
10k
require(ESM)とECMAScript仕様
uhyo
7
2k
TypeScript Quiz (Encraft #12 Frontend Quiz Night)
uhyo
8
1.7k
Shadow DOMとCSSの現状
uhyo
11
7.4k
Other Decks in Programming
See All in Programming
フロントエンドのディレクトリ構成どうしてる? Feature-Sliced Design 導入体験談
osakatechlab
8
4.1k
LLM Supervised Fine-tuningの理論と実践
datanalyticslabo
4
1.1k
SymfonyCon Vienna 2025: Twig, still relevant in 2025?
fabpot
3
1.2k
KMP와 kotlinx.rpc로 서버와 클라이언트 동기화
kwakeuijin
0
140
PHPで作るWebSocketサーバー ~リアクティブなアプリケーションを知るために~ / WebSocket Server in PHP - To know reactive applications
seike460
PRO
2
120
ゆるやかにgolangci-lintのルールを強くする / Kyoto.go #56
utgwkk
1
370
モバイルアプリにおける自動テストの導入戦略
ostk0069
0
110
CSC305 Lecture 26
javiergs
PRO
0
140
数十万行のプロジェクトを Scala 2から3に完全移行した
xuwei_k
0
270
テストケースの名前はどうつけるべきか?
orgachem
PRO
0
130
42 best practices for Symfony, a decade later
tucksaun
1
180
開発者とQAの越境で自動テストが増える開発プロセスを実現する
92thunder
1
180
Featured
See All Featured
Designing Experiences People Love
moore
138
23k
Adopting Sorbet at Scale
ufuk
73
9.1k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
A Tale of Four Properties
chriscoyier
157
23k
Producing Creativity
orderedlist
PRO
341
39k
Facilitating Awesome Meetings
lara
50
6.1k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
2
290
A Philosophy of Restraint
colly
203
16k
Documentation Writing (for coders)
carmenintech
66
4.5k
The Invisible Side of Design
smashingmag
298
50k
Designing for Performance
lara
604
68k
Faster Mobile Websites
deanohume
305
30k
Transcript
App Router時代のデータ 取得アーキテクチャ 2023-08-02 What's "Next" JS Meetup 基調講演 uhyo
(株式会社バベル プリンシパルエンジニア)
登壇者紹介 uhyo 2022年10月から株式会社バベル勤務。 設計やレビューを中心としつつ、 何でも屋として活動。 TypeScript入門書 好評発売中! 今年も増刷した→
会社紹介 株式会社バベル 社名のわりにJavaScriptのビルドに Babelを使っていないことで有名。 “世界中の人々の役に立つ事業を創り続ける”をミッションとする
プロダクト紹介 商談解析クラウド セールス分野をターゲットとし、営業現場の業務効率化 と「売れる」営業人材の育成を支援する。 • オンライン商談を録画し、AIが解析 • 効率的に見返しフィードバックすることができる • 議事録にもなる
復習のコーナー
Next.jsって何だっけ? Reactアプリケーション向けに、 主にルーターとサーバー実装を提供してくれる フレームワーク • ルーター: URLに応じてコンテンツを出し分ける機構 • サーバー実装: いわゆるSSRやキャッシュの機能を担当
あとバンドルの最適化まわりを頑張ってくれる
App Routerって何だっけ? Next.js 13で追加された、新しいルーターの実装。 従来のPages Routerと対比してApp Routerと 呼ばれる 特徴: •
React Server Components (RSC) の上に作られている • Pages Routerには無いさまざまな機能
レンダリング 最も単純なルーター location.href switch文的な何か ルーティング定義 DOM
レンダリング ファイルシステムベースルーティング ルーティング定義がファイルシステム上で行われるもの。 フレームワークが好んで採用する傾向にある location.href switch文的な何か ルーティング定義 ファイル システム DOM
レンダリング SSR機能 サーバー クライアント リクエストURL switch文的な何か HTML文字列 DOM バンドルされた JavaScript
ハイドレーション クライアント側ナビゲーションのときも追加のバンドルを取得したりする動きがあるが省略。 以降もナビゲーションの話は特筆すべき事情がない限り省略します レンダリング
データフェッチングって? アプリケーションの外部からデータを取得し、表示に 利用すること。 SSRしないアプリケーションであれば、普通にクライア ントからfetchしてあとは煮るなり焼くなりすれば いい。 SSRする場合は話がややこしく、フレームワークが サポートしてくれる。 ※ そもそもSSRすべきかどうかの話は別の話題なので、場外乱闘はお控えください
React 18より前の事情 サーバーサイドレンダリング用のAPI(renderToStringとか)は 同期的なレンダリングを行うAPIである。 → レンダリングの最中にデータフェッチングを行うのは不可。 → Reactアプリケーションの外部のAPIを使うことになる。 • getServerSidePropsとかそのあたり
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がもたらした変化
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 RSCはフレームワークを介して使うことが多い。フレー ムワークは普通SSRもサポートしているので、実用上は RSCとSSRを併用することが多い。 ※ いわゆるSGとかその辺りはSSRに対する最適化とみなして、 このトークでは全部まとめてSSRとして取り扱います
レンダリング (サーバー側) RSC + SSR サーバー クライアント DOM Reactアプリケーション サーバー側
+ クライアント側 Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション
レンダリング (サーバー側) RSC + SSR サーバー DOM Reactアプリケーション サーバー側 +
クライアント側 Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション ここがSSR要素 (本来クライアント側で行うレ ンダリングをサーバー側でも行 う)
RSCとデータフェッチング RSCは、サーバー側コンポーネント内で直接データ フェッチングできることを売りのひとつとしている。 • コンポーネントをasync関数にできる • →やはり状態管理無しでデータフェッチング可能
サーバー クライアント レンダリング(サーバー側) RSC + SSR DOM Reactアプリケーション サーバー側 +
クライアント側 Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション データフェッチング
RSCとデータフェッチングのポイント データフェッチングがレンダリング(サーバー側)に 含まれているため、SSRしてもサーバー側とクライアン ト側で処理が重複しない。 ハイドレーションのために面倒なことを考える必要が ない。 レンダリング(サーバー側) データフェッチング
昔のNext.jsとの比較 昔のNext.js RSC(サーバー側) リクエスト データフェッチング レンダリング HTML文字列 getServerSidePropsとか レンダリング(サーバー側) レンダリング
(クライアント側) HTML文字列 データフェッチング リクエスト
昔のNext.jsとの比較 データフェッチングに着目して比較すると、 共通点: • (クライアント側の)レンダリングより前に データフェッチングを済ませてしまうので、 ハイドレーション周りの面倒ごとが無い。 異なる点: • データフェッチングをReactアプリのレンダリングの一部
として行うか否か。
昔のNext.jsとの比較 Q. RSCでは、なぜデータフェッチングがReactアプリの 外からReactアプリの中に移動したのか?
昔のNext.jsとの比較 Q. RSCでは、なぜデータフェッチングがReactアプリの 外からReactアプリの中に移動したのか? A. データフェッチングの方法の標準化のため ※もちろん理由は1つではないが、この理由は確かDan先生がTwitter(当時)で言っていた
昔のNext.jsとの比較 昔のNext.js リクエスト データフェッチング レンダリング HTML文字列 getServerSidePropsとか レンダリング(サーバー側) レンダリング (クライアント側)
HTML文字列 データフェッチング リクエスト RSCの導入により、Next.jsの独 自概念が要らなくなった
昔のNext.jsとの比較 Q. RSCでは、なぜデータフェッチングがReactアプリの 外からReactアプリの中に移動したのか? A. データフェッチングの方法の標準化のため 昔のgetServerSideProps等はReact外の概念だったが、 新しいAPI (headers()とか)はRSCの上に作られている。 フレームワーク独自の機構が減り、フレームワーク間での共通化が進んだ。
(Reactが定める“標準”に合わせた機構となった) (RSCを受け入れないフレームワークは別)
App Router時代の データ取得アーキテクチャ
データ取得のポイント 目指すべき目標: サーバー側とクライアント側の連携をRSCに任せ、 ユーザーランドで苦労しない。 ユーザーランドの苦労の例: GraphQLクライアントのキャッシュをサーバー側からクライアント側に コピーするとか
サーバー クライアント レンダリング(サーバー側) RSC + SSR(再掲) DOM Reactアプリケーション サーバー側 +
クライアント側 Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション データフェッチング
サーバー クライアント レンダリング(サーバー側) RSC + SSR(再掲) DOM Reactアプリケーション サーバー側 +
クライアント側 Reactアプリケーション ただのHTML + クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション データフェッチング RSCによるサーバー・クライア ント連携部分
ユーザーランドで苦労しないために データ取得はサーバー側とクライアント側の2種類に 分けてけて考えよう。 • サーバー側データ取得: SSR結果(=初期レンダリング結果)に反映されてほしいもの • クライアント側データ取得: 初期レンダリングには含まれなくていいもの
サーバー クライアント レンダリング(サーバー側) DOM Reactアプリケーション サーバー側 + クライアント側 Reactアプリケーション ただのHTML
+ クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション データフェッチング サーバー側データフェッチング クライアント側データ フェッチングを発火
サーバー クライアント レンダリング(サーバー側) DOM Reactアプリケーション サーバー側 + クライアント側 Reactアプリケーション ただのHTML
+ クライアント側 バンドルされた JavaScript レンダリング (クライアント側) HTML文字列 レンダリング (クライアント側) ハイドレーション データフェッチング ポイント: ここで データフェッチング をしない
ユーザーランドで苦労しないために ポイント: Reactアプリ内でデータ取得を行えるというRSCの利点 を生かしつつSSR周りの苦労をしないために、 サーバー側で行う必要があるデータ取得は全部 Server Component内で行う。 RSCがやってくれる以外でサーバー側と クライアント側のデータ共有をしようとしない。
Server Component内の データフェッチングについて 各論1
Fetch on render でいいのか? Fetch on renderは、コンポーネントがレンダリング されたらそのコンポーネントが必要とするデータの取得 が始まることを指す。 レンダリング
→ fetch → レンダリング → 次のfetch ……という流れで通信を直列化させる問題がある。
Fetch on render でいいのか? サーバーサイドでは、fetchにかかる時間が短いことが多 い。(Next.jsサーバーとDBが同じデータセンターにあ る場合など) この場合、サーバー側コンポーネントはFetch on renderでも問題ないと考えられる。
(少なくとも、パフォーマンスボトルネックが他の場所に移る可能性は高そう)
SC内のデータフェッチング Fetch on Renderが許容されるので、上流コンポーネン トに取得をまとめるといった工夫を考える必要がない。 よって、Server Component内ではデータを必要とする コンポーネントが各々勝手にデータを取得してもよい。 ※リクエストをまとめたい別の事情があることも考えられるので、最終的には各自の事情を鑑みて判断しよう
Server Componentの テスト 各論2
データフェッチング周りのテスト BFF的なロジックをReact内で書くとなると、 それに対するユニットテストを書きたくなる。 Server Componentのテストはどうするのが良いか?
データフェッチング周りのテスト BFF的なロジックをReact内で書くとなると、 それに対するユニットテストを書きたくなる。 Server Componentのテストはどうするのが良いか? A. クライアント用コンポーネントのテストと 考え方は同じ
テストに対する考え方2案 • 普通にSCをレンダリングしてテストする。 • 今はまだできないが、そのうちできるようになる cf. https://github.com/testing-library/react-testing-library/issues/1209 • コンポーネントそのものではなく、ロジックを関数に 抜き出してテストする。
• レンダリングされるHTMLをユニットテストする必要がない場合も多 く、ロジックをフックに抜き出してテストすれば十分だったりする。 • SCではフックですらなくただのasync関数として抜き出せるので、 むしろテストしやすいかも
クライアント側の 状態管理との連携 各論3
RSCと状態管理の懸念 従来のReactでは、データフェッチングの結果は一種の 「状態」として扱われてきた。 cf. 「3種類」で管理するReactのState戦略 一方、SCでのデータフェッチング結果は、クライアント から見たら「上からpropsで降ってくる値」であり、 もはや状態ではない。
RSCと状態管理の懸念 問題: SCがフェッチした状態に関してsource of truthが React内にあるので、一部の状態管理アーキテクチャと の相性が微妙 • ReduxとかRecoil型アーキテクチャでは状態管理をReactコン ポーネントから分離しているので、Reactの中→外
という微 妙なデータの流れが必要になる。 ※Recoilでは正確にはRecoilRootの中にあるが、アーキテクチャ的な話
RSCと状態管理の懸念 答えはまだない。 RSCと相性抜群な(クライアント用)状態管理アーキテ クチャを発明したらウケるかも?
まとめ App Router時代のデータ取得のポイントは、とにかく ハイドレーション周りの苦労を減らすこと。 そのためには、サーバー側にデータ取得を寄せるのが有効。 いわゆるFetch on Renderもわりと許容できる。 クライアント側状態管理との連携どうしたものか。誰か教えて ほしい
お約束
バベルでは商談解析クラウド を一緒に開発・ 運用するエンジニアを募集しています • TypeScriptでフロント・バックエンド両方書く感じ • テックリード・EMになりたい方も歓迎! • メールやTwitter(通称)でご連絡お待ちしています •
カジュアルな面談できます 📧
[email protected]
𝕏 @uhyo_ 採用情報