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
React への依存を最小にするフロントエンド設計
Search
ONDA, Takashi
November 22, 2024
Programming
29k
28
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
React への依存を最小にするフロントエンド設計
JSConf JP 2024 での発表資料です
ONDA, Takashi
November 22, 2024
More Decks by ONDA, Takashi
See All by ONDA, Takashi
Rust で関数型ドメインモデリング
takonda
0
190
Make Illegal States Unrepresentable
takonda
2
250
細粒度リアクティブステートのスコープとライフサイクル
takonda
2
6.7k
Remix で middleware
takonda
1
1.4k
TSKaigi Kansai 2024 - 構造的部分型と serialize 境界
takonda
3
1.7k
Remix Way を外れる自由
takonda
2
650
一休レストランで Next.js App Router から Remix に乗り換えた話 / Migration from Next.js App Router to Remix
takonda
14
8.9k
Other Decks in Programming
See All in Programming
自サークルのIdPからログアウトできるようになるまで
taiseiue
1
150
なぜCTOを降りてFDEを選んだのか?〜なぜプロダクト企業がFDEで顧客の現場に踏み込むのか〜
gonta
1
230
SalesForceを内製化!? ~ HR事業を支える顧客管理基盤のインフラを大公開 ~
oku053
0
190
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
180
No More NoSuchMethodError
exoego
1
110
機械に任せるテスト、人が見るテスト ⽣成AIで引き直した、運⽤保守フェーズの線引き
dske104
0
200
[JA] Domain Modeling with Vanilla Rails: 「操作」から再考するRailsの設計論
yasaichi
4
830
残高管理から台帳サービスへの進化
artoy
1
210
PyConTW 2026 - AI Coding 不只是工具升級, 區域醫院醫療資訊系統協作開發與資訊團隊轉型實踐
cclai999
0
150
When benchmarks go bad - what I learned from measuring performance wrong
hollycummins
0
240
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
370
Lambda durable functionsでHuman in the Loopを楽に…楽に……
har1101
1
190
Featured
See All Featured
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
640
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
2
2.9k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.4k
Ethics towards AI in product and experience design
skipperchong
2
440
The Pragmatic Product Professional
lauravandoore
37
7.5k
How GitHub (no longer) Works
holman
316
150k
What the history of the web can teach us about the future of AI
inesmontani
PRO
2
750
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.5k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.6k
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
2
960
Transcript
React への依存を最小にする フロントエンド設計 株式会社一休 CTO 室 恩田 崇
2 自己紹介 株式会社一休 CTO 室 恩田 崇 1978 年生まれ、京都在住 フルスタック、なんでも屋
一休レストランのフロントエンドアーキテクト Next.js App Router を Remix に書き換えた フロントエンドとは IE4/DHTML あたりから
3 依存が最小になっているとは? Remix の様々な adapter @remix-run/express @remix-run/cloudflare-workers @fastly/remix-server-adapter @vercel/remix Hono
Cloudflare, Fastly, Deno, Bun, AWS, Node.js 昨日 remix-hono-adapter が Node.js 対応した フレームワーク自体が好例 ` ` ` ` ` ` ` `
4 依存が最小になっているとは? Vanilla JS で書かれた部分の多さ → React なしで使えるコードがどれだけあるか → testing-library
なしでテストが書ける部分がどれだけあるか 一休レストランでは testing-library を使っていない 今日の話における定義、スコープを共有
5 目次 なぜ依存を最小にするのか? 技術選定 設計 一休レストランでの実践 今日お話しすること
6 なぜ依存を最小にするのか? エコシステムの変化に追随する負担を減らしたい フレームワークを切り替えたい よりよい設計を求めて 複数の動機
7 なぜ依存を最小にするのか? 一休レストランは2006 年から プロダクトはフレームワークより長寿命になることがある 2006 年というと… スマートフォンはまだない Chrome もない
(2008 年) jQuery 1.0 がリリース 近日中に確実に来るメジャーバージョンアップ React 19 React Router v7 (f.k.a. Remix v3) エコシステムの変化に追随する負担を減らしたい
8 なぜ依存を最小にするのか? 2022 年末にリニューアルプロジェクト開始 旧版は Vue 2 / Nuxt 2
TypeScript で書かれている 旧版のコードをそのまま持ってこれない Vue / Nuxt を駆使している → 言い換えれば Vue / Nuxt にがっつり依存 Remix への移行 2023 年10 月 Next.js App Router でリリース 2023 年12 月 Remix に切り替えた フレームワークを切り替えたい
9 なぜ依存を最小にするのか? 初期に React 初心者がやらかしがちなコードが量産された 大きなコンポーネント コンポーネントにロジックが詰まっている 大量の useState 大量の
useEffect 見通しが悪くコードの理解が難しい テストを書くのが困難 よりよい設計を求めて
10 目次 なぜ依存を最小にするのか? 技術選定 設計 一休レストランでの実践 今日お話しすること
11 技術選定 React に依存しないライブラリ 薄いフレームワーク 依存を最小化するにも基盤が必要
12 技術選定 swr → TanStack Query Recoil → Jotai XState
( 自作に置き換え中) いずれも Vanilla JS で使えるライブラリ React に依存しないライブラリ
13 技術選定 規約より API 規約への依存は見えない ファイル名、ディレクトリ構造 変数や関数名 明示的な API は参照箇所を追える
React Router v7 から config base routing が! 標準 API の尊重 独自 API を使うところは少ない方が嬉しい 今だと Remix や Hono エスケープハッチ フレームワークの敷いてくれたレールを外れたいときがある 薄いフレームワーク
14 目次 なぜ依存を最小にするのか? 技術選定 設計 一休レストランでの実践 今日お話しすること
15 設計 依存を最小化するという考え方が古くからある オブジェクト指向とその爆発的な流行 テスト駆動開発 バックエンドの知見に倣う
16 設計 依存性逆転の原則 (Dependency Inversion Principle) 腐敗防止層 (Anti Corruption Layer)
バックエンドの知見に倣う
17 設計 依存性逆転の原則 (Dependency Inversion Principle)
18 設計 腐敗防止層 (Anti Corruption Layer)
19 目次 なぜ依存を最小にするのか? 技術選定 設計 一休レストランでの実践 今日お話しすること
20 一休レストランでの実践 hooks にできるかぎりロジックを書かない export function useEventNavigate() { return useSetAtom(eventNavigate$)
} const eventNavigate$ = atom(null, async (get, set, event) => { const env = get(env$) const navigate = get(navigate$) const { pathname, search } = get(location$) const current = get(historyState$) // snip })
21 一休レストランでの実践 コンポーネントは薄く小さく const styles = sva({ /* snip */
}) function IkyuPoint() { const { totalPoint, enabled, onChange } = useIkuPoint() const classes = styles() if (totalPoint === 0) { return ( <div className={classes.head}> <h2 className={classes.title}>保有ポイント</h2> <p className={classes.message}>保有ポイントはありません</p> </div> ) } // snip }
22 一休レストランでの実践 Jotai で関数を管理することで簡易的な DI コンテナとしても利用 依存性逆転の原則と Dependency Injection function
functionAtom<F extends Function>( fn: F ): WritableAtom<F, [F], void> { const wrapper = atom({ fn }) return atom<F, [F], void>( (get) => get(wrapper).fn, (_get, set, fn) => { set(wrapper, { fn }) } ) }
23 一休レストランでの実践 Date を使わず日付や時刻を表す型を作成 graphql-codegen で Custom Scalar として利用 Temporal
がいずれは base line に Java はかつて java.util.Date から Date-Time API に移行した 腐敗防止層 const zDateText = z .string() .regex(/^\d{4}-\d{2}-\d{2}$/) .brand('DateText') type DateText = z.infer<typeof zDateText> // HourMinute, DateTime など ` `
24 一休レストランでの実践 test('日付変更で、選択されている時間帯にもっとも近い予約可能な時間を設定', async () => { const fetchTimes =
vi.fn().mockResolvedValue({ /* snip */ }) const { transition } = createStateMachine({ fetchTimes }) const current = createCurrent() const result = await transition( current, calendarEvent('selectVisitDate', { visitDate: '2024-10-26' as DateText }) ) expect(result.value).toEqual('READY') expect(result.context).toEqual({ ...current.context, visitDate: '2024-10-26', selectedVisitDate: '2024-10-26', visitTime: '18:30', }) })
25 エンジニア募集中! 一休では、よりよいサービスを届ける仲間を募集しています。