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
Yohei Iino
February 23, 2024
Technology
150
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
App Routerの紹介
Yohei Iino
February 23, 2024
More Decks by Yohei Iino
See All by Yohei Iino
1年半放置したExpo製アプリを最新化してみた
wheatandcat
0
100
作成中のFlutterアプリの中間発表
wheatandcat
0
83
最近読んだ技術書を簡単紹介
wheatandcat
0
110
ユニバーサルリンク/アプリリンクを使ってQRコードでゲストログインできるようにする
wheatandcat
0
380
Firebase App Checkを実装したので紹介
wheatandcat
0
310
PlanetScaleの無料プランがなくなるので、NeonとTiDBを試してみた
wheatandcat
0
410
Flutter HooksとRiverpodの解説
wheatandcat
0
580
T3 Stack(応用編: Next Auth & SSRの実装紹介)
wheatandcat
1
400
Flutter × GraphQLでアプリを作ってみる
wheatandcat
0
340
Other Decks in Technology
See All in Technology
徹底討論!ECS vs EKS!
daitak
3
1.8k
週末にループ・エンジニアリングの理解を深めるためのスライド
nagatsu
0
550
10年間のブログ発信を振り返って見えたWebアプリケーションエンジニアとしての軌跡
stefafafan
0
190
AIAU_UMEMOGU_ninomiya_slide
ninomiya_ii
0
270
Amazon Redshift zero-ETL 統合を活用した軽量なマルチプロダクトデータ可視化基盤 / Lightweight Multi-Product Data Visualization with Amazon Redshift Zero-ETL
kaminashi
0
110
FPC(フレキシブル)基板にZephyr実装してみた。
iotengineer22
0
180
Fabricをフル活用する AI Agent Hub -製造業特化AIエージェントの設計
iotcomjpadmin
0
150
MySQL & MySQL HeatWave Report - June 2026
freshdaz
0
190
AI-DLCを “そのまま導入しなかった”話 ~組織に合わせてアジャストした 私たちの実践共有~
hiroramos4
PRO
1
440
Hatena Engineer Seminar 37 jj1uzh
jj1uzh
0
140
脱SaaS!FDEを支えるプロビジョニングと分離設計
knih
0
300
ぼっちではじめた登壇が「51名」「241件」の発信に化けた
subroh0508
1
330
Featured
See All Featured
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
240
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
How to Think Like a Performance Engineer
csswizardry
28
2.7k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
170
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
400
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Code Reviewing Like a Champion
maltzj
528
40k
The SEO Collaboration Effect
kristinabergwall1
1
490
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
250
Transcript
App Routerの紹介 Press Space for next page
自己紹介 📝 飯野陽平(wheatandcat) 🏢 法人設立(合同会社UNICORN 代表社員) 💻 Work: シェアフル株式会社CTO 📚
Blog: https://www.wheatandcat.me/ 🛠 今までに作ったもの memoir ペペロミア MarkyLinky
App Routerとは? Next.js 13.4で追加された新しいルーティング機構 従来のNext.jsのルーティングはPage Router RSC(React Server Components)の使用を前提と設計
RSC(React Server Components) とは? Reactでサーバーサイドでレンダリングできるコンポーネントを宣言できる仕組み 元々、Reactにはクライアントサイドでレンダリングするクライアントコンポーネントしかなかった SSRは、クライアントコンポーネントをサーバーサイドでレンダリングする仕組み RSCを使用することでサーバーサイド固有の機能を実装できる 例えばReact内で直接データベースにアクセスすることなどが可能 逆にRSCではクライアントサイド固有の機能は使用できない
例えば、useStateやuseEffectなどのHooksは使用できない 宣言した時点でエラーになる RSCで宣言されたコンポーネントはブラウザ側で読み込みbundleされたJavaScriptには含まれないため、読 み込むファイルサイズは小さくなる
App Routerのルーティング基本機構 従来のPage Routerのルーティング機構 App Routerのルーティング機構 src └─ pages ├─
index.tsx → / └─ items ├─ [id].tsx → /items/[id] └─ [id] └─ share.tsx → /items/[id]/share src └─ app ├─ page.tsx → / └─ items └─ [id] ├─ page.tsx → /items/[id] └─ share └─ page.tsx → /items/[id]/share
ルーティング毎に動的にfavicon、OG画像を変更する App Routerのルーティング機構だと以下のように設定が可能 以下、書き方の参考 src/app/icon.tsx src └─ app ├─ layout.tsx
→ 共通設定 └─ items └─ [id] ├─ icon.tsx → 動的favicon を変更 └─ opengraph-image.tsx → 動的OG 画像を変更
データアクセス & レンダリングの構造① App RouterはデフォルトはRSCでレンダリングされる、以下、コードの例 export default function Home() {
return ( <div className="container"> <h1 className="text-5xl"> Sample App </h1> <CrudShowcase /> </div> ); } async function CrudShowcase() { const session = await getServerAuthSession(); if (session?.user) { const url = await api.url.existsByUserId.query({userId: String(session?.user.id)}); if (url) redirect(`/schedule/${String(url?.id)}`); } return <CreateUrl />; }
データアクセス & レンダリングの構造① App RouterはデフォルトはRSCでレンダリングされる、以下、コードの例 async function CrudShowcase() { export
default function Home() { return ( <div className="container"> <h1 className="text-5xl"> Sample App </h1> <CrudShowcase /> </div> ); } const session = await getServerAuthSession(); if (session?.user) { const url = await api.url.existsByUserId.query({userId: String(session?.user.id)}); if (url) redirect(`/schedule/${String(url?.id)}`); } return <CreateUrl />; }
データアクセス & レンダリングの構造① App RouterはデフォルトはRSCでレンダリングされる、以下、コードの例 const session = await getServerAuthSession();
if (session?.user) { const url = await api.url.existsByUserId.query({userId: String(session?.user.id)}); if (url) redirect(`/schedule/${String(url?.id)}`); } export default function Home() { return ( <div className="container"> <h1 className="text-5xl"> Sample App </h1> <CrudShowcase /> </div> ); } async function CrudShowcase() { return <CreateUrl />; }
データアクセス & レンダリングの構造① App RouterはデフォルトはRSCでレンダリングされる、以下、コードの例 return <CreateUrl />; export default
function Home() { return ( <div className="container"> <h1 className="text-5xl"> Sample App </h1> <CrudShowcase /> </div> ); } async function CrudShowcase() { const session = await getServerAuthSession(); if (session?.user) { const url = await api.url.existsByUserId.query({userId: String(session?.user.id)}); if (url) redirect(`/schedule/${String(url?.id)}`); } }
データアクセス & レンダリングの構造② "use client"; export function CreateUrl() { const
router = useRouter(); const createMutation = api.url.create.useMutation({ onSuccess: (data) => { router.push(`/items/${data.id}`); }, }); const onCreate = useCallback(() => { createMutation.mutate(); }, [createMutation]); return ( <button className="button" onClick={onCreate} > 新しいデータを作る </button> ); }
データアクセス & レンダリングの構造② "use client"; export function CreateUrl() { const
router = useRouter(); const createMutation = api.url.create.useMutation({ onSuccess: (data) => { router.push(`/items/${data.id}`); }, }); const onCreate = useCallback(() => { createMutation.mutate(); }, [createMutation]); return ( <button className="button" onClick={onCreate} > 新しいデータを作る </button> ); }
データアクセス & レンダリングの構造② export function CreateUrl() { const router =
useRouter(); const createMutation = api.url.create.useMutation({ onSuccess: (data) => { router.push(`/items/${data.id}`); }, }); const onCreate = useCallback(() => { createMutation.mutate(); }, [createMutation]); return ( <button className="button" onClick={onCreate} > 新しいデータを作る </button> ); } "use client";
データアクセス & レンダリングの構造③ RSCではasync/awaitが使用できる RSCではhooksは使用できないのでデータ更新で使用するuseMutationはクライアントコンポーネントで実 装する必要がある RSCでデータ取得する場合は、直接データベースにアクセスが可能なので以下のように実装が可能 export default async
function Page({ params }: { params: { id: string } }) { const session = await getServerAuthSession(); const url = await api.url.exists.query({ id: params.id }); if (url === null) { // 存在しないURL の場合はトップページに戻す redirect("/"); } ... 省略
データアクセス & レンダリングの構造③ RSCではasync/awaitが使用できる RSCではhooksは使用できないのでデータ更新で使用するuseMutationはクライアントコンポーネントで実 装する必要がある RSCでデータ取得する場合は、直接データベースにアクセスが可能なので以下のように実装が可能 export default async
function Page({ params }: { params: { id: string } }) { const session = await getServerAuthSession(); const url = await api.url.exists.query({ id: params.id }); if (url === null) { // 存在しないURL の場合はトップページに戻す redirect("/"); } ... 省略
データアクセス & レンダリングの構造③ RSCではasync/awaitが使用できる RSCではhooksは使用できないのでデータ更新で使用するuseMutationはクライアントコンポーネントで実 装する必要がある RSCでデータ取得する場合は、直接データベースにアクセスが可能なので以下のように実装が可能 const url =
await api.url.exists.query({ id: params.id }); if (url === null) { // 存在しないURL の場合はトップページに戻す redirect("/"); } export default async function Page({ params }: { params: { id: string } }) { const session = await getServerAuthSession(); ... 省略
実装してみる PR: App Routerに変更する 以下、デモしながら説明 App Routerの移行で以下の処理はシンプルに実装できた例1 旧コード 新コード App
Routerの移行で以下の処理はシンプルに実装できた例2 旧コード 新コード
まとめ App RouterはRSCを前提としたルーティング機構になっている RSCを使用するとデータ取得周りはシンプルに実装できる ただ、App Routerはフロントエンド界隈では賛否両論で、当面Web文脈では議論されていきそう 一休レストランで Next.js App Router
から Remix に乗り換えた話 元々Next.jsはWeb標準のAPIに準拠していないことが問題視されていて、App Routerでより、その点が 強まった 逆にRemixはWeb標準のAPIに準拠した思想で実装されているので対象的になっている
ご清聴ありがとうございました 🎉