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
useSyncExternalStoreを使いまくる
Search
TOMIKAWA Sotaro
December 10, 2024
Programming
7k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
useSyncExternalStoreを使いまくる
TOMIKAWA Sotaro
December 10, 2024
More Decks by TOMIKAWA Sotaro
See All by TOMIKAWA Sotaro
ReactとSvelteのその先、Ripple-TS / Beyond React and Svelte: Ripple-TS
ssssota
3
2.6k
Atomics APIを知る / Understanding Atomics API
ssssota
2
1.4k
なんでRustの環境構築してないのにRust製のツールが動くの? / Why Do Rust-Based Tools Run Without a Rust Environment?
ssssota
15
56k
Web技術を最大限活用してRAW画像を現像する / Developing RAW Images on the Web
ssssota
2
3.3k
漸進。
ssssota
0
3.7k
Preact、HooksとSignalsの両立 / Preact: Harmonizing Hooks and Signals
ssssota
1
3.8k
React CompilerとFine Grained Reactivityと宣言的UIのこれから / The next chapter of declarative UI
ssssota
8
6.3k
新しいAPI createRawSnippet触ってみた / What is the createRawSnippet?
ssssota
2
340
脱法Svelte / Evasion of svelte rules
ssssota
1
350
Other Decks in Programming
See All in Programming
DroidKaigi 2026 「個人開発という実験場: Android エンジニアが手にする4つの自由」
slashnephy
0
220
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
0
140
片田舎のおっさん、 Swift Buildのダイアモンド問題解決の不具合修正PRを出すが、解決方法がキャッシュをしないようにすることであり、ビルド時間が伸びると言われてマージされないので高速化もする/swiftbuild
yimajo
0
360
Can LLMs Replicate 4 Years of Compose Migration? Exploring the boundaries of automation with 279 XML files from a real product
makun
0
130
まだ間に合う!今年の夏こそSchemeのマクロ展開器を完全理解!
omasanori
0
630
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
2
330
AI に Inclusive UI を書かせよう — Design Rules Skill で Compose UI を作り直す
theoriatec2024
1
450
20260828_品質と開発生産性を両立させる、AI時代のE2Eテストの考え方
magicpod
0
160
コンパウンドプロダクト開発のためのローカルプロセスマネージャー再発明 #layerxgo
izumin5210
0
640
AI時代に学ぶ 好きなルール 嫌いなルール Linter編
shorty5121
0
860
AIと壁打ちしながら進めるコスト管理
fufuhu
2
1.9k
Building an Out-of-Order CPU
latte72
0
680
Featured
See All Featured
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
490
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
690
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
510
From π to Pie charts
rasagy
0
350
Ruling the World: When Life Gets Gamed
codingconduct
0
320
Between Models and Reality
mayunak
4
450
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
410
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
360
Crafting Experiences
bethany
1
290
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
970
Transcript
useSyncExternalStoreを 使いまくる 株式会社ユーザベース×株式会社ZOZO×株式会社PR TIMES 3社合同フロントエンド勉強会 株式会社ZOZO ブランドソリューション開発本部WEARフロントエンド部Webブロック 冨川宗太郎 Copyright ©
ZOZO, Inc. 1
© ZOZO, Inc. 株式会社ZOZO ブランドソリューション開発本部 WEARフロントエンド部Webブロック 冨川 宗太郎 2022年 ZOZOに新卒入社。
WEARのWeb開発に従事。テックリードを務める。 趣味はOSSとカメラ。 2
© ZOZO, Inc. https://wear.jp/ 3 • あなたの「似合う」が探せるファッションコーディネートアプリ • 1,700万ダウンロード突破、コーディネート投稿総数は1,400万 件以上(2024年9月末時点)
• コーディネートや最新トレンド、メイクなど豊富なファッション 情報をチェック • AIを活用したファッションジャンル診断や、フルメイクをARで試 せる「WEARお試しメイク」を提供 • コーディネート着用アイテムを公式サイトで購入可能 • WEAR公認の人気ユーザーをWEARISTAと認定。モデル・タレン ト・デザイナー・インフルエンサーといった各界著名人も参加
© ZOZO, Inc. 4 WEAR Webの今と役割 WEAR (wear.jp) は絶賛リプレイス中! VBScriptという古の言語で一部稼働しており、
Next.js(Pages Router) / React環境に移行中。 服でお困りのユーザーにGoogleなどの検索で辿り着いてもらい、 多くのユーザーにファッションの参考にしてもらうのが使命。 リプレイスだけではなく日々改善を積み重ねていく必要がある... 今日はそんな前提の話。
© ZOZO, Inc. 5 改善のために ひと口に改善といっても守らなければいけないラインがある。 • リプレイス前環境の制約 ◦ 認証・認可
• リプレイスに基づく制約 ◦ パスの最適化 • 各種キャッシュ • etc... 他所への影響を最小限に抑えながら素早く改善したい。 できればABテストで影響も見ながら。
© ZOZO, Inc. 6 方針 Next.jsのMiddlewareでCookie(非HttpOnly) にABテスト設定を注入 クライアントサイドJSでCookieを読んで表示制御 • HTTPメッセージをほとんど汚染せず(Set-Cookieのみ)
• キャッシュの邪魔もせず • ユーザー別のUIが表示できる
© ZOZO, Inc. 7 middleware export const middleware: NextMiddleware =
(req) => { const res = NextResponse.next(); res.cookies.set( COOKIE_NAME, random(PATTERN_A, PATTERN_B), ); return res; }; ヨシ。
© ZOZO, Inc. 8 コンポーネント export const Component: React.FC =
() => { const pattern = getCookie(COOKIE_NAME); if (pattern === PATTERN_A) return ...; // PATTERN_B return ...; }; SSRできない。(getCookieはクライアントサイドでのみ使えるものとする)
© ZOZO, Inc. 9 SSR対応 export const Component: React.FC =
() => { const pattern = typeof window !== undefined ? getCookie(COOKIE_NAME) : PATTERN_B; if (pattern === PATTERN_A) return ...; // PATTERN_B return ...; }; SSRするとHydration Errorが発生する。
© ZOZO, Inc. 10 useEffectでマウント後に取得 export const Component: React.FC =
() => { const [pattern, setPattern] = useState(PATTERN_B); useEffect(() => { setPattern(getCookie(COOKIE_NAME)); }, []); if (pattern === PATTERN_A) return ...; // PATTERN_B return ...; }; クライアントサイドレンダリングでも無駄な再描画が発生する。
© ZOZO, Inc. export const Component: React.FC = () =>
{ const pattern = useSyncExternalStore( () => () => {}, () => getCookie(COOKIE_NAME), () => PATTERN_B, ); if (pattern === PATTERN_A) return ...; // PATTERN_B return ...; }; 11 useSyncExternalStore
© ZOZO, Inc. 12 useSyncExternalStoreとは 公式ドキュメント(https://ja.react.dev/reference/react/useSyncExternalStore) useSyncExternalStore は、外部ストアへの サブスクライブを可能にする React
のフックです。 外部ストア?サブスクライブ?
© ZOZO, Inc. 13 useSyncExternalStoreとは 基本は「第2引数の返り値を返す」フック。 const value = useSyncExternalStore(
() => () => {}, () => "#zup_frontend", ); return value; // "#zup_frontend" ... なにがうれしいんだっけ?
© ZOZO, Inc. 14 唯一無二 第三引数 SSR時とHydration時は、第2引数の代わりに第3引数に渡した関数が実行される const value =
useSyncExternalStore( () => () => {}, () => "Now CSR (window/document are available)", () => "Now SSR or Hydrating", ); ブラウザ側でしか使えない関数やリソースを必要な時だけ利用できる。 Hydration Errorの回避にも使える。
© ZOZO, Inc. 15 () => () => {} 第1引数のコレ↑はなに?
外部ストアへのサブスクライブ をするための関数。 サブスクライブ(=購読≃同期)をする必要がないときは () => () => {} この形になる。
© ZOZO, Inc. 16 第1引数 第1引数をもう少し細かく確認する。リアルな例を見てみる。 createdAtをHydrationに配慮しながらフォーマットする例: const formatted =
useSyncExternalStore( (callback) => { const id = setInterval(callback, 60 * 1000); return () => clearInterval(id); }, () => formatTimeDelta(new Date(createdAt)); () => new Date(createdAt).toISOString(); );
© ZOZO, Inc. 17 第1引数 Reactの外にある何か(window,document,store,etc...)と同期したいときに利用。 const subscribe = (callback)
=> { // 値などが変化したらcallbackを呼ぶ const unsubscribe = () => { // コンポーネントが破棄されるときに呼ばれる }; return unsubscribe; }; callbackが呼ばれると、第二引数に渡した関数が再評価されて値が変化する。
© ZOZO, Inc. 18 使い方いろいろ • Hydration Error回避 • mediaQuery
(window.matchMedia) • ResizeObserver • localStorage • navigator.onLine • フレームワークを跨いだsignal/store同期 • 独自store実装 • navigator.canShare • クライアント限定fetch処理 • etc...
© ZOZO, Inc. 19 useSyncExternalStore ロジックを分離しやすいインターフェース。 クライアントサイドロジックとの親和性が非常に高い。 まずは自作storeからはじめてみよう!
None