Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Server Component を理解する(したい)
Search
morio
July 24, 2023
42
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Server Component を理解する(したい)
morio
July 24, 2023
More Decks by morio
See All by morio
行送りと実装
mrtgm
0
43
なぜ Riverpod か?
mrtgm
0
18
Featured
See All Featured
How to make the Groovebox
asonas
2
2.5k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
450
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.5k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
How Software Deployment tools have changed in the past 20 years
geshan
2
35k
Abbi's Birthday
coloredviolet
4
10k
Optimizing for Happiness
mojombo
378
71k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
Git: the NoSQL Database
bkeepers
PRO
433
67k
Heart Work Chapter 1 - Part 1
lfama
PRO
10
37k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
780
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
Transcript
React Server Component を理解する(したい)
それってなに? • サーバだけで動く React のコンポーネント • 2018 年に発表され、2020 年に最初の RFC
が出た • https://github.com/reactjs/rfcs/blob/main/text/0188-server-componen ts.md • 2022年12月に出た Next.js 13 の App Router でパンピーも試せるようになった • 現時点で唯一のフレームワークに載った RSC の実装 • 先月に出た Next.js 13.4 で App Router は stable になりました
何が嬉しいの?
とりあえず実装してみた • Next.js で、同じ内容のアプリを App Router と Page Directory で作ってみ
る • Todo アプリ • DB あり • Todo の作成/削除 • Todo のトグル • Todo の検索
これまで • DB へのアクセスは API Routes を立てて行う • マウント時、useEffect で
API に問い合わせ • クライアントで state 作ってデータ入れる
登場人物紹介 • Server Component(SC) • サーバでしか実行されないコンポーネント • hooks(useState, useEffect)、イベントハンドラが使えない •
Client Component(CC) ◦ サーバ、クライアントで実行されるコンポーネント ◦ これまでのコンポーネントと同じ ▪ hooks、イベントハンドラが使える • app directory のコンポーネントは基本 SC • “use client” で CC
App Router • API は立てる必要なし、コンポーネントの中で直接 DB へのアクセスを記 述していい • Server
Actions で更新系も表現可能 • useEffect は不要 • コンポーネントのトップレベルで await する • Suspense 使える • 問い合わせの結果を保持する state は不要 • クライアントに配信する JS のサイズも減る
何を解決したかったのか?
この動画を見てください https://www.youtube.com/watch?v=TQQPAU21ZUw
Network Waterfall https://17.reactjs.org/docs/concurrent-mode-suspense.html#traditional-approaches -vs-suspense
const Todo = () => { useEffect(()=> { fetchTodo().then((v) =>
setTodo(v)); }, []) if(!todo) return <>Loading…</> return (<> … <Author /> </>) } const Author = () => { useEffect(()=> { fetchAuthor().then((v) => setAuthor(v)); }, []) if(!author) return <>Loading…</> return (<> … <Tag /> </>) const Tag = () => { useEffect(()=> { fetchTag().then((v) => setTag(v)); }, []) if(!tag) return <>Loading…</> return (<> … </>) }
Fetch-on-render
const Todo = () => { const fetchAll = async
() => { await Promise.all([ fetchTodo(), fetchAuthor() fetchTag() ]).then(([todo, author,tag]) => { setTodo(todo) setPosts(posts) setTag(tag) }) } useEffect(()=> { fetchAll() }, []) if(!todo) return <>Loading…</> … }
Fetch-then-render
Render-as-you-fetch
Relay Relay (Meta 製 GraphQL Client)は、Fetch-on-render のように colocation し つつ、
Render-as-you-fetch へ移行する方法を提供する https://relay.dev/docs/guided-tour/rendering/queries/#render-as-you-fetch • Fragment でコンポーネント自身のコードとデータ取得のコードを並置 • 親で一括でデータ取得することで、Waterfall を避ける • Suspense でローディング境界を定義できる Relay & GraphQL じゃないと最高になれないのか?😡
ところで Waterfall が悪いのは、 サーバ/クライアント間の、インターネットを挟ん だ通信だから
None
コンポーネントをサーバに持ってきたら?
React Server Component
というわけで RSC は、GraphQL や Relay などのライブラリに依存せず、React のコアで Waterfall 問題を解決しようとするもの サーバ/DB間であれば
Waterfall があったとしても程度を抑えられる そしたら他にもいいことがあった: • バンドルサイズ削減 • コードスプリットの自動化
React でやれる旨み これらの問題は、React がクライアント志向であるために生じていたものです。PHPやRailsのような伝統 的なサーバレンダリングに回帰しても問題は解決できるでしょうが、インタラクティブ性を担保すること が難しくなってしまいます。ここには「薄い」クライアントか「厚い」クライアント、どちらを使うべき かというアプリケーション開発の積年の対立構造があります。 結局、純粋なサーバレンダリング、あるいはクライアントレンダリングでは不十分なのです。サーバレン ダリングではデータを素早く取得・表示できる一方、クライアントレンダリングではリッチな体験や、高 速なフィードバックを実現できます。しかし、どちらもやろうとすると、それぞれに対応する2つの言語
やフレームワークを導入することになってしまったり、ロジックの重複が生じがちでした。 サーバコンポーネントは単一の言語・フレームワーク、つまり React でサーバとクライアントのいいとこ 取りを試みるものです。 https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md#distinct-challenges-unified -solution
どうやっているのか - JSX ツリーをシリアライズしたものをサーバから送信 - HTML は送らない - クライアントでデシリアライズして、クライアント側のツリーとマージし て更新
• https://github.com/reactwg/server-components/discussions/5(最初に php のコードが出てきたりしておもろい) • https://www.plasmic.app/blog/how-react-server-components-work
None
1⃣: サーバにページの JSX をシリアライズして送るようリクエスト JSX は React.createElement() の糖衣構文 { "type":
"div", "key": null, "ref": null, "props": { "children": "hoge" }, "_store": {} } console.log(<div>hoge</div>) →
2⃣: サーバでデータを取得してシリアライズ シリアライズはサーバで行われるので、SC では Node.js の API を使える シリアライズ不能なものは SC
の props に書けない(イベントハンドラ) → const Post = async ({postId}) => { const data = await db.findOne(...) return (<main> .... </main>) }; { “type”: “main”, “props”: { “children”: [ { … } } }
3⃣: JSON を独自のフォーマットに変換し、クライアントに送る Stream で、データ取得の状態を送付したいため M1:{"id":"./src/ClientComponent.client.js","chunks":["client1"],"name":""} J0:["$","@1",null,{"children":["$","span",null,{"children":"Hello from server land"}]}]
const Fetcher = async () => { const data =
await fetch(…) return … } const Parent = () => { <> parent <Suspense fallback="loading"> <Fetcher /> </Suspense> </> } J0:["$","",null,{"children”:[“parent”,[“$”,”$2",null,{"fallback”:”loading”,”children”:”…”}]]}] S2:"react.suspense" J0:["$","",null,{"children”:[“parent”,[“$”,”$2",null, …]]}]
4⃣: クライアントでデータを受け取り、JSXにデシリアライズする • その際CCの参照が含まれる場合は動的に import しつつ、復号された JSX に マージ •
こうすることでCCのステートを保持しつつ、更新(mutation, navigation)が あった場合は新しいデータで画面を更新できる
SSR と RSC はどう違うのか? - SSR と RSC は別物で、併用可能 App
Router では、初回アクセスは HTML を SSR で返し、以降は RSC のフォーマットでやり取りする
まとめ • RSC とは、React チームが勧める新しいデータ取得のための戦略 ◦ Server Component と Client
Component がある ◦ データ取得をよりいい感じに書ける ◦ Waterfall の解決が元々のモチベーション ◦ SPA に、MPA の良いところを取り込む • プロダクション投入できる? ◦ Server Actions が stable になるまでは早いかも