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
48
15k
App Router時代のデータ取得アーキテクチャ
2023-08-02 What's "Next" JS Meetup
uhyo
August 02, 2023
Tweet
Share
More Decks by uhyo
See All by uhyo
tsconfig.jsonの最近の新機能 ファイルパス編
uhyo
6
1.7k
非同期処理を活用しながらRust製wasmとJSを連携する方法(wasm-bindgenを使いたくない人向け)
uhyo
4
3.4k
tsconfig.jsonの設定を見直そう!フロントエンド向け 2024夏
uhyo
25
8k
React 19を概念から理解する
uhyo
21
9.3k
require(ESM)とECMAScript仕様
uhyo
6
1.8k
TypeScript Quiz (Encraft #12 Frontend Quiz Night)
uhyo
8
1.6k
Shadow DOMとCSSの現状
uhyo
11
7.1k
TypeScriptってどんな言語? 言語そのものを知る面白さ
uhyo
16
8.8k
ステート管理を超えるRecoil運用の考え方
uhyo
15
12k
Other Decks in Programming
See All in Programming
C#および.NETに対する誤解をひも解く
ymd65536
0
290
DevFest Android in Korea 2024 - 안드로이드의 문단속 : 앱을 지키는 암호화 이야기
mdb1217
1
160
NEWTにおけるiOS18対応の進め方
ryu1sazae
0
230
Beyond Laravel Octane - Hyperf for Laravel Artisans
albertcht
1
140
XP2024 っていう国際会議に行ってきたよの記
bonotake
4
240
タイミーにおけるデータの利用シーンと データ基盤の挑戦
marufeuille
4
3.2k
Cloud Adoption Frameworkにみる組織とクラウド導入戦略(縮小版)
tomokusaba
1
210
게임 개발하던 학생이이 세계에선 안드로이드 개발자?
pangmoo
0
110
DjangoNinjaで高速なAPI開発を実現する
masaya00
0
510
Memory API: Patterns, Use Cases, and Performance
josepaumard
1
170
WEBアプリケーションにおけるAWS Lambdaを用いた大規模な非同期処理の実践
delhi09
PRO
7
4.2k
個人開発で使ってるやつを紹介する回
yohfee
1
700
Featured
See All Featured
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
504
140k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
225
22k
Reflections from 52 weeks, 52 projects
jeffersonlam
346
20k
Automating Front-end Workflow
addyosmani
1365
200k
Robots, Beer and Maslow
schacon
PRO
157
8.2k
Product Roadmaps are Hard
iamctodd
PRO
48
10k
No one is an island. Learnings from fostering a developers community.
thoeni
19
2.9k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
4
120
Agile that works and the tools we love
rasmusluckow
327
21k
Keith and Marios Guide to Fast Websites
keithpitt
408
22k
VelocityConf: Rendering Performance Case Studies
addyosmani
325
23k
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_ 採用情報