Slide 1

Slide 1 text

Sync と Async useSyncExternalStore を使う者の 岐路 2026/06/06 Musubi AI在庫管理チーム 江藤 優汰 フロントエンド・PHPカンファレンス北海道2026 © KAKEHASHI Inc.

Slide 2

Slide 2 text

名前: 江藤 優汰 担当プロダクト: Musubi AI在庫管理 役職: ソフトウェアエンジニア 普段はPythonでバックエンドを書いている ことが多い フロントエンド開発をもっとやりたい! 自己紹介 © KAKEHASHI Inc. 2

Slide 3

Slide 3 text

カケハシは薬局・医療の現場を支えるプロダクトを開発しています。 日本の医療体験を、しなやかに。 © KAKEHASHI Inc. 3

Slide 4

Slide 4 text

薬局向けの在庫管理プロダクト 欠品・過剰在庫による治療遅延・業務負荷増 加、保管スペースの圧迫と管理の手間という 課題がある AI による需要予測で発注を最適化 Musubi AI在庫管理 © KAKEHASHI Inc. 4

Slide 5

Slide 5 text

業務時間で技術トピックを深掘りするコミュニティ フロントエンド研究会 もそのひとつ 毎週話題を持ち寄って集まったり、Slackで気軽にレビューなど依頼できる カケハシには「研究会」文化がある © KAKEHASHI Inc. 5

Slide 6

Slide 6 text

1 Async React と出会う © KAKEHASHI Inc.

Slide 7

Slide 7 text

ある日、研究会のSlackに通知が来た © KAKEHASHI Inc. 7

Slide 8

Slide 8 text

AI在庫もReact使っているけど、フロントエンドに詳しいメンバーいないから調べてみようかな 🤔 © KAKEHASHI Inc.

Slide 9

Slide 9 text

UIの更新は、状態の取得もレンダリングも全てが非同期プロセスである。 そもそも Async React とは? © KAKEHASHI Inc. 9

Slide 10

Slide 10 text

AI在庫管理でも Async React の考え方を取り入れて開発していきたい! どんな API があるんだろう…? 自分のプロダクトでも使いたい! © KAKEHASHI Inc. 10

Slide 11

Slide 11 text

useTransition / startTransition Suspense useDeferredValue useOptimistic ViewTransition 主要な API © KAKEHASHI Inc. 11

Slide 12

Slide 12 text

2 試してみる © KAKEHASHI Inc.

Slide 13

Slide 13 text

トランジションを試してみる const [isPending, startTransition] = useTransition(); const handlePageChange = (next: number) => { startTransition(() => { setPage(next); }); }; const MedicineStockPage = () => { const { page, setPage } = usePage(); return ( }> ); }; © KAKEHASHI Inc. 13

Slide 14

Slide 14 text

Suspenseフォールバックは最初の一回のみで、以降は useTransition の isPending でローディングされるはず (デモであり実際のAI在庫管理の画面ではありません) 0:00 / 0:05 試してみよう! © KAKEHASHI Inc. 14

Slide 15

Slide 15 text

なぜかページ移動でSuspenseフォールバックが表示されてしまう、、、 (デモであり実際のAI在庫管理の画面ではありません) 0:00 / 0:07 何かがおかしい、、、 © KAKEHASHI Inc. 15

Slide 16

Slide 16 text

AI在庫では状態管理に Zustand を使っています Zustand は内部的に useSyncExternalStore を使用しています ここが怪しいのでは、、、? 実は… © KAKEHASHI Inc. 16

Slide 17

Slide 17 text

3 原因を探る © KAKEHASHI Inc.

Slide 18

Slide 18 text

useSyncExternalStore から返される値に基づいてレンダーをサスペンド させることは推奨されていません。 外部ストアで起きた変更は ノンブロッキン グ型のトランジション更新としてマークできない ため、直近の Suspense フ ォールバックが起動してしまいます。 既に画面上に表示されているコンテンツ がローディングスピナで隠れてしまうため、通常は望ましくないユーザ体験につ ながります。 https://ja.react.dev/reference/react/useSyncExternalStore useSyncExternalStore のドキュメントを確認してみる © KAKEHASHI Inc. 18

Slide 19

Slide 19 text

So, in this proposal: Updates triggered by a store change will always be synchronous, even when wrapped in startTransition https://github.com/reactjs/rfcs/blob/main/text/0214-use-sync-external-store.md#detailed-design 訳)この提案では、ストア変更による更新は startTransitionで包んでも常に 同期的。 useSyncExternalStore の同期レンダリングは仕様であることがわかる RFC にも © KAKEHASHI Inc. 19

Slide 20

Slide 20 text

useState / useReducer は複数バージョンの状態を持てる 「画面に表示されている状態」と「裏で組み立てられている状態」を持てる React 組み込み API なのでトランジション前提で設計されている なんでトランジションとしてマークされないの? © KAKEHASHI Inc. 20

Slide 21

Slide 21 text

外部ストアは1つの状態しか持てない 外部のストアは React の世界の外にあるので、複数バージョンを持てない (実装次第で持てはするが、React側がどのバージョンを参照するか決める 仕様がない) もしトランジションに対応させると、レンダリングの途中でストアが変わってティ アリング(コンポーネント間で見える値が食い違う) が起きる useSyncExternalStore は状態の同期を優先し、トランジションは仕様として非 対応 なんでトランジションとしてマークされないの? © KAKEHASHI Inc. 21

Slide 22

Slide 22 text

useSyncExternalStoreが解決したいティアリングとは? © KAKEHASHI Inc. 22

Slide 23

Slide 23 text

4 岐路 © KAKEHASHI Inc.

Slide 24

Slide 24 text

そもそも外部ストアである必要があるか考える useState に置き換えてもいいなら置き換える ライブラリを変える jotai は意図的に useSyncExternalStore を採用していない トレードオフとしてティアリングを受け入れる設計になっている zustand ベースの別解として use-zustand というのもある jotai と同じく useSyncExternalStore を使わない設計になっている じゃあ、どうしよう? © KAKEHASHI Inc. 24

Slide 25

Slide 25 text

React チームは useSyncExternalStore の課題を解決する別 API を開発中 待っていれば、この「岐路」自体が消える可能性もある。(が現時点で進展はなさ そうに見える) https://react.dev/blog/2025/04/23/react-labs-view-transitions-activity-and-more#concurrent-stores ちなみに:Concurrent Stores © KAKEHASHI Inc. 25

Slide 26

Slide 26 text

Async React の考え方をチームで理解 useSyncExternalStore の仕様を理解した上でトランジションで更新しないよう にする(とはいえ気にし続けるのも難しい気がする) 全てをトランジションにする前提で考えるなら、 use-zustand を使うのもあ り https://speakerdeck.com/uhyo/react-19shi-dai-nokonponentoshe-ji-besutopurakuteisu?slide=22 AI在庫管理は、まず何から始めよう? © KAKEHASHI Inc. 26

Slide 27

Slide 27 text

useSyncExternalStore の "Sync" は仕様。トランジション / Suspense と は本質的に相性が悪い部分がある しかしこれはバグではなく設計通りの挙動 AI在庫管理の今後 Async React の考え方を取り入れていきたい 状態管理ライブラリ zustand の置き換えは重いので、ひとまずは use- zustand を採用してみる まとめ © KAKEHASHI Inc. 27

Slide 28

Slide 28 text

No content