Slide 1

Slide 1 text

Redux → Recoil → Zustand → useSyncExternalStore: 状態管理の10年とReact本来の姿 株式会社ZOZO
 計測プラットフォーム開発本部 計測システム部 フロントエンドブロック
 林 恭央 Copyright © ZOZO, Inc. 1

Slide 2

Slide 2 text

© ZOZO, Inc. 株式会社ZOZO 計測プラットフォーム開発本部 計測システム部 フロントエンドブロック 林 恭央 2021年12月中途で株式会社ZOZOに入社。 計測プロダクトのフロントエンド開発に従事。 ZOZOMAT計測で靴のサイズは26.5。 ZOZOGLASSでは【濃いめトーンのクールカラー】判定。 2

Slide 3

Slide 3 text

© ZOZO, Inc. 3 https://zozo.jp/zozomat/ ● 自宅にいながら簡単に高精度な足の3D計測ができる計測マット ● 計測したデータをもとに、自分の足型と靴の“相性度” を表示 ● NIKEやCONVERSEなど7,500型以上のアイテムに対応 (2025年9月末時点)

Slide 4

Slide 4 text

© ZOZO, Inc. 4 https://zozo.jp/zozoglass/ ● 自宅で簡単・高精度にご自身の顔の肌の色を計測できる フェイスカラー計測ツール ● ECにおけるコスメ購入時の課題であった「色選び」に 関する不安や悩みを解消 ● 肌の色を構成する成分、ヘモグロビン量とメラニン量を 画像から推定 ● コスメ専門モール「ZOZOCOSME」で取り扱うベース メイクの一部に対応 ● 計測者数140万人を突破(2025年9月末時点)

Slide 5

Slide 5 text

© ZOZO, Inc. 5 この10年のReact状態管理の変遷 Reactが2013年に登場して以来、 UI構築の中心課題は「状態をどこに、どうもつか?」だった。 10年の間にその解釈は様々に変化し、ライブラリの進化は 「状態管理の再発明の歴史」といえる。

Slide 6

Slide 6 text

© ZOZO, Inc. 6 Fluxアーキテクチャがもたらした転換 2014年頃、Facebookが提示したFluxアーキテクチャは、Reactコンポーネント 間でデータの流れが複雑化する問題を解決するために考案された。 MVC(Model-View-Controller)の双方向データフローが抱える 「どこでデータが変わったのか分かりづらい」という課題を解消するため。 Fluxの要点は「単方向データフロー(Unidirectional Data Flow)」 これにより、状態変化の経路が明確に。 デバッグ可能性と予測可能性が格段に向上した。

Slide 7

Slide 7 text

© ZOZO, Inc. 7 Redux時代:明示的フローと制御の厳格さ ● 状態を「一元管理」する思想 ● Action・Reducer・Storeによる副作用の明確化 ● メリット:予測可能性/ツールチェーン(Redux DevTools) ● デメリット:ボイラープレート/過剰な構造

Slide 8

Slide 8 text

© ZOZO, Inc. 8 状態を「一元管理」する思想 Reduxは「全てのアプリケーション状態を単一のStoreで管理する」という設計思想を持 つ。 このStoreはアプリ全体の状態をツリー構造で保持し、どのコンポーネントからも参照で きる唯一の情報源( Single source of truth)となる。 これにより、 以下の項目が実現された。 ● どこに何の状態があるのかが一意に定まり ● 複数コンポーネント間の状態同期によるバグが減少 ● Undo/Redoやデバッグの容易化

Slide 9

Slide 9 text

© ZOZO, Inc. 9 Action・Reducer・Storeによる副作用の明確化 状態変更は必ずAction→Reducer→Storeの流れで行われる。 ● Action...「何をしたか」の定義(ex. INCREMENT) ● Reducer...Actionと現在のstateから新しいstateを返す関数(純粋関数として実装) ● Store...Reducerで返された新しいstateを保持 この明示的な流れのおかげで、副作用・状態変更の発生箇所が限定され、予測可能な プログラムが書けるようになる。

Slide 10

Slide 10 text

© ZOZO, Inc. 10 Reduxの実装例 const INCREMENT = 'INCREMENT'; const increment = () => ({ type: INCREMENT }); function counterReducer(state = 0, action) { switch(action.type) { case INCREMENT: return state + 1; default: return state; } } このようにReduxは「状態管理をあえて厳格に一元化」し、「副作用を純粋関数により明示化」したことで、複雑な UIの信頼性・可観測性を高めたが、同時に開発効率面で課題も生んだ。

Slide 11

Slide 11 text

© ZOZO, Inc. 11 Recoil時代:宣言的・粒度の細かい依存モデル ● Reactチーム提供の“公式っぽい”分散状態管理 ● atom/selectorsの思想とReact Suspenseとの統合 ● パフォーマンスよりも「React的思考」に寄せたデザイン

Slide 12

Slide 12 text

© ZOZO, Inc. 12 Reactチーム提供の“公式っぽい”分散状態管理 RecoilはMeta(旧Facebook)のReactチームが開発した、コンポーネントごとに細かく状 態を分割できる設計。 従来のReduxのような「単一Storeに集約」から、「複数の atom(状態の粒)」 を宣言的 に定義するスタイルに進化した。

Slide 13

Slide 13 text

© ZOZO, Inc. 13 atom/selectorsの思想とReact Suspenseとの統合 Selectorはatomなど複数の状態を合成・派生させるための“導関数”。 ● 他のatom/selectorの値から動的に計算結果を返すことで、状態の依存関係や再 計算コストが最小化される ● Selectorのget関数は純粋関数で記述され、依存グラフを自動で最適化する Suspenseと統合することで、非同期の状態データ(例:APIフェッチ)が自然にUIと連携 できる。 → “ローディング”/“エラー”表示がReact標準の機能に組み込まれ、体験とコードが一致 する。

Slide 14

Slide 14 text

© ZOZO, Inc. 14 atom/selectorsの思想とReact Suspenseとの統合 import { selector } from 'recoil'; const filteredBookListState = selector({ key: 'FilteredBookList', get: ({get}) => { const list = get(bookListState); // フィルタ条件による派生例 return list.filter(item => item.available); } });

Slide 15

Slide 15 text

© ZOZO, Inc. 15 パフォーマンスよりも「React的思考」に寄せたデザイン Recoilは「状態がどこから発生し、どのコンポーネントが依存しているか」 を、Reactの 再レンダリング・依存管理モデルと一体化させて設計した。 ● 必要な部分だけ再描画し、不必要な再レンダリングを回避 ● Reduxなどの“厳格な構造”ではなく、「Hooksで直感的に使えるAPI」 ● イミュータブルな値の流通や依存性を抽象的に“宣言”できる React公式の思考に沿うことで、複雑なアプリほど「何が変わると何が動くか」がわかり やすく、スケールしやすい実装が可能になった。

Slide 16

Slide 16 text

© ZOZO, Inc. 16 Zustandの出現:軽量・関数的・フック一発 ● Reduxの“重さ”への反発 ● create/store による極小API ● Immerベースによる更新の簡潔さ ● server components時代への自然な接続

Slide 17

Slide 17 text

© ZOZO, Inc. 17 Reduxの“重さ”への反発 Zustandは、「Reduxの厳格でボイラープレートが多い設計」に対する反発から 生まれた、超軽量・関数的志向の状態管理ライブラリ。 Reduxの導入には多くの設定やファイル分割が必要だったが、 Zustandは「set関数とstore作成だけ」でグローバルステートの扱いが可能とな る。

Slide 18

Slide 18 text

© ZOZO, Inc. 18 create/store による極小API import { create } from 'zustand'; const useStore = create((set) => ({ count: 0, increment: () => set((state) => ({ count: state.count + 1 })), reset: () => set({ count: 0 }) })); // どこからでも const { count, increment } = useStore(); ● Contextをラップ不要: ProviderやReducerも不要 ● Hooksだけで完結: 必要なstateを必要な場所で呼ぶスタイル ● 最小構成: 1ファイルで十分に稼働し、状態の配置も任意 この「極小API」のため、導入・学習コストも非常に低い

Slide 19

Slide 19 text

© ZOZO, Inc. 19 Server Components時代への自然な接続 React 18以降で公式に導入された useSyncExternalStore は、Zustandでも内部 的に利用されている。 また、React Server Component により、UI の一部がサーバーでレンダリングさ れるようになった。 これにより、サーバーコンポーネントとクライアント側の状態管理との橋渡しが 保証され、SSR と CSR を意識せずに安全に利用できるようになっている。 ● クライアント側でインタラクティブな状態を 安全&シンプルに管理する方法が重要に ● 外部ストアとの同期もReact標準に準拠

Slide 20

Slide 20 text

© ZOZO, Inc. 20 useSyncExternalStore:Reactが状態管理を取り戻した瞬間 ● React 18で導入された公式インターフェース ● 外部ストアとの同期を標準化する意義 ● Redux・Zustand・Jotai などが同APIで統一される流れ

Slide 21

Slide 21 text

© ZOZO, Inc. 21 React 18 で導入された公式インターフェース ● useSyncExternalStoreはReact 18で公式APIとして追加されたフック。 ● ReactコンポーネントがReact自体の管理外にある外部ストア(Reduxや Zustand、ブラウザAPIなど)と安全・整合的に同期できる仕組みを標準化。

Slide 22

Slide 22 text

© ZOZO, Inc. 22 外部ストアとの同期を標準化する意義 ● 従来、外部ストアの変更検知や再描画には独自の仕組みや回避策 (useEffect, subscribe/unsubscribe)が必要だった。 ● useSyncExternalStoreの3つの引数で、「購読(subscribe)」「スナップ ショット取得(getSnapshot)」「SSR・Hydration初期値 (getServerSnapshot)」をReactと外部ストア共通のインターフェースと して扱える。 ● これにより、状態の正確な同期・予測可能な再レンダリングが保証される。

Slide 23

Slide 23 text

© ZOZO, Inc. 23 外部ストアとの同期を標準化する意義 import { useSyncExternalStore } from 'react'; // 外部ストア例 function useCustomStore() { return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); }

Slide 24

Slide 24 text

© ZOZO, Inc. 24 Redux・Zustand・Jotaiなどが同APIで統一される流れ ● Redux, Zustand, Jotaiなど近年の主流状態管理ライブラリは内部実装で useSyncExternalStoreを利用し、React標準APIとの親和性が大幅に向上し た。 ● 全ての外部ストアが同じAPIで「状態の一元的な参照・更新」ができる時代 に。 ● サーバーコンポーネント/クライアントコンポーネント間のhydration・同 期も安全に一貫性を保てる。

Slide 25

Slide 25 text

© ZOZO, Inc. 25 まとめ:Reactの“本来の姿”とは何か ● Reactの本質は「宣言的・同期的なUIファースト」。 人間との対話を最適化するためのUI記述言語であり、状態管理はその同期と 安全性を支える役割へと収束した。 ● 状態はUIと分離されるのではなく「同期される対象」 ● useSyncExternalStore が示す “minimal but canonical” な方向性 Reactは「UI構築に集中するためのプラットフォーム」。 その進化の中で状態管理は 「外部同期を最小限かつ公式に担保する」姿へと到達した。

Slide 26

Slide 26 text

No content