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
React 19を概念から理解する
Search
uhyo
May 28, 2024
Technology
21
8.9k
React 19を概念から理解する
2024-05-29うひょさんに聞く! React 19アップデートの勘所
#React19_Findy
uhyo
May 28, 2024
Tweet
Share
More Decks by uhyo
See All by uhyo
非同期処理を活用しながらRust製wasmとJSを連携する方法(wasm-bindgenを使いたくない人向け)
uhyo
4
3k
tsconfig.jsonの設定を見直そう!フロントエンド向け 2024夏
uhyo
22
7.3k
require(ESM)とECMAScript仕様
uhyo
6
1.6k
TypeScript Quiz (Encraft #12 Frontend Quiz Night)
uhyo
8
1.6k
Shadow DOMとCSSの現状
uhyo
11
6.9k
TypeScriptってどんな言語? 言語そのものを知る面白さ
uhyo
16
8.7k
App Router時代のデータ取得アーキテクチャ
uhyo
48
15k
ステート管理を超えるRecoil運用の考え方
uhyo
15
12k
ついに来る!TypeScript5.0の新機能
uhyo
21
16k
Other Decks in Technology
See All in Technology
Javaにおける関数型プログラミンへの取り組み
skrb
5
110
エンジニア採用を起点に取り組む組織の改善活動と課題、中長期のタスク管理/ #HRmethod
nishiuma
4
3.3k
Building Static Websites with Sculpin
opdavies
0
1.4k
Autonomous Database Cloud 技術詳細 / adb-s_technical_detail_jp
oracle4engineer
PRO
15
39k
LLMに日本語テキストを学習させる意義
ksaito
13
3.4k
X-Correlation Injections (or How to break server-side contexts)
fransrosen
0
360
【Λ(らむだ)最近のアプデ情報 / RPALT20240904
lambda
0
160
バックログを導入し やっぱやめた話
ota42y
0
170
疎通2024
sadnessojisan
4
490
PlaywrightによるE2Eテスト入門 / Introduction to E2E Testing with Playwright
rhumie
3
910
React Aria で実現する次世代のアクセシビリティ
ryo_manba
3
290
デジタル化・DX推進あるある
y150saya
0
220
Featured
See All Featured
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
27
8.9k
[RailsConf 2023] Rails as a piece of cake
palkan
44
4.6k
Mobile First: as difficult as doing things right
swwweet
220
8.8k
Building Better People: How to give real-time feedback that sticks.
wjessup
359
18k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
225
22k
Writing Fast Ruby
sferik
623
60k
Web Components: a chance to create the future
zenorocha
308
41k
The Mythical Team-Month
searls
218
43k
Intergalactic Javascript Robots from Outer Space
tanoku
268
26k
Being A Developer After 40
akosma
82
580k
The Language of Interfaces
destraynor
153
23k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
354
29k
Transcript
React 19を 概念から理解する 2024-05-29うひょさんに聞く! React 19アップデートの勘所 #React19_Findy
発表者紹介 uhyo 株式会社カオナビ フロントエンドエキスパート ずっとTypeScriptとReactで仕事している。 好きなReactの機能はやっぱりSuspense。
React 19 RC 4月25日にBeta、 5月15日にRCが 公開。あわせて ブログも公開された。 https://react.dev/blog/2024/04/25/react-19
This Talk React 19 RCのブログ記事や、すでに公開 されているReactのドキュメントをベースに React 19の機能を解説。 具体的なAPIを細かく見ていくというよりは、 React
19時代に重要になる大まかな概念を 理解することを目指す。
Reactのこれまで React 0.14 … 神話の時代 React 15 … クラスコンポーネント全盛期 React
16 … フックの時代(正確には16.8から) React 17 … No New Features React 18 … Suspenseの時代
React 19は何の時代になる?
React 19は何の時代になる?
React 19は何の時代になる? React 0.14 … 神話の時代 React 15 … クラスコンポーネント全盛期
React 16 … フックの時代(正確には16.8から) React 17 … No New Features React 18 … Suspenseの時代 React 19 … Actionsの時代
Actionsとは?
Actionsとは?
Actionsとは? By convention, functions that use async transitions are called
“Actions”. 非同期トランジションを使う関数のことを、 慣例的に “Actions” と呼ぶことにします。
Actionsとは? By convention, functions that use async transitions are called
“Actions”. 非同期トランジションを使う関数のことを、 慣例的に “Actions” と呼ぶことにします。 ?
余談: Reactのドキュメントについて より分かりやすくActionsを説明したいところだが、 発表者の経験的に、Reactの新概念は めちゃくちゃ調べたり実験したりして自分なりの 素晴らしい説明が書けたと思ったら、 公式ドキュメントに同じことが最初から書いてあった ということがよくある。
余談: Reactのドキュメントについて なので、公式の情報に正面から向き合い、 書いてあることを全部妥協せずに理解するのが Reactの新概念を深く正確に理解する最短ルート である。 (現時点ではまだドキュメントの更新が追いついていない ところもありそうなので、実験と気合で補いましょう)
Actionsとは? By convention, functions that use async transitions are called
“Actions”. 非同期トランジションを使う関数のことを、 慣例的に “Actions” と呼ぶことにします。
非同期トランジションとは トランジションという概念は、React 18ですでに 導入されていた。(useTransition) 非同期の部分はReact 19の新しい概念である。 ページ遷移とかで使われるView Transition APIは関係ないので 気を付けよう!
CSSのtransitionも関係ないです
トランジションの復習 (React 18でのトランジション) const [isPending, startTransition] = useTransition(); // イベントハンドラとかで
startTransition(() => { setIsOpen(true); // 何らかのステート更新 });
トランジションの復習 startTransition(() => { setIsOpen(true); // 何らかのステート更新 }); startTransitionのコールバック内で行われた ステート更新はトランジションとなり、
優先度が低いステート更新として扱われる。
トランジションの性質 普通のステート更新: 更新後のレンダリング結果をすぐに・絶対に描画する。 レンダリングに時間がかかる場合、完了するまで 次のステート更新はできない。 優先度が低いステート更新(トランジション): レンダリングに時間がかかる場合は描画を遅延できる。 別のステート更新で割り込んだり、ステートを 再度更新してレンダリングをキャンセルしたりできる。
isPendingの挙動 const [isPending, startTransition] = useTransition(); トランジションの場合、ステート更新の結果が即座にUIに 反映されないこともある。その間、isPendingがtrue で レンダリングされる。
(トランジションのステート更新の反映はまだされずに、 isPendingだけがtrueになる)
Suspenseとトランジションの関係 トランジションのステート更新によって サスペンドが発生した場合も、レンダリングに 時間がかかる場合に準じた扱いとなる。 ステート更新後のUI(=Suspenseのfallback)が 出る代わりに、更新前のUIを維持したままで isPendingがtrueになる。 (優先度の低いステート更新なので更新前のUIを維持することが許容される)
Suspenseとトランジションの雑な例 const [userId, setUserId] = useState(0); const userProfile = use(dataSource.getUser(userId));
// … startTransition(() => { setUserId(123); // ステート更新したらサスペンド発生 });
React 18までのトランジションまとめ 優先度の低いステート更新をするためのAPI。 時間のかかるレンダリングの最中に 他のステート更新を受け付けたり、 サスペンドを起こしたレンダリングの最中に サスペンド前のUIを残し続けたり することができる。
宣伝 React 18までのトランジションについて、 細かな挙動まで含めて解説したZenn本
React 19の非同期トランジション startTransition(async () => { const result = await
updateStuff(); setMessage( result.success ? “success!” : “ouch!” ); }); 非同期関数を渡せる (この非同期関数がアクション)
React 19の非同期トランジション startTransition(async () => { const result = await
updateStuff(); setMessage( result.success ? “success!” : “ouch!” ); }); 非同期トランジションの実行中は isPendingがtrueになる。 完了したらfalseに戻る。 もちろん、トランジション内 でステート更新できる。
React 19の非同期トランジション 非同期処理の間isPendingがtrueになる点で、 非同期トランジションの挙動は、 普通のトランジション + Suspenseと同じ。 Q. どちらを使えばいいか?
React 19の非同期トランジション 非同期処理の間isPendingがtrueになる点で、 非同期トランジションの挙動は、 普通のトランジション + Suspenseと同じ。 Q. どちらを使えばいいか? A.
参照系はSuspense、更新系は非同期トランジション Suspenseは参照系向けのAPIで、更新系には向いて いなかった。非同期トランジションでそこが補完された。
React 19の非同期トランジション 公式ドキュメントにも Actions automatically manage submitting data for you
という記載があり、 非同期トランジション(アクション)が更新系の サポートを意図したAPIであることが分かる。
アクションに関係する新しいAPI •useOptimistic • UIの楽観的更新を書きやすくするためのフック •useActionState • アクションの状態管理を楽に行うためのフック
useOptimistic
useOptimisticによる楽観的更新 楽観的更新とは、更新リクエストを送ったあと、 レスポンスが返ってくる前に更新後の状態を UIに反映させること。 例: Xで「いいね」を押すと、押した瞬間にUI上では いいね数が1増える(レスポンスが返ってくるのを待たない)
楽観的更新の面倒さ ステート管理が煩雑になりがち。 • エラー時に戻すことを考えると、元データを上書きできない • エラー時にステートを戻す処理を行いたいので ErrorBoundaryを活かせない
useOptimisticの使い方(宣言側) const [likes, setLikes] = useState(0); const [dispLikes, addOptimistic] =
useOptimistic( likes, (currentLikes, optimisticValue) => { return currentLikes + optimisticValue; } );
useOptimisticの使い方(宣言側) const [likes, setLikes] = useState(0); const [dispLikes, addOptimistic] =
useOptimistic( likes, (currentLikes, optimisticValue) => { return currentLikes + optimisticValue; } ); 元データの“楽観的更新版”のステートを宣言できる。 楽観的更新版 元データ
useOptimisticの使い方(更新側) const [dispLikes, addOptimistic] = useOptimistic(…); startTransition(async () => {
addOptimistic(1); // 楽観的更新で1を足す const newLikes = await api.postLike(); setLikes(newLikes); // 元データを更新 });
useOptimisticの使い方(更新側) const [dispLikes, addOptimistic] = useOptimistic(…); startTransition(async () => {
addOptimistic(1); // 楽観的更新で1を足す const newLikes = await api.postLike(); setLikes(newLikes); // 元データを更新 }); 非同期トランジションの中でaddOptimisticを呼び出す ことで、楽観的更新として反映される。
useOptimisticの動作例 const [likes, setLikes] = useState(0); const [dispLikes, addOptimistic] =
useOptimistic( likes, (currentLikes, optimisticValue) => { return currentLikes + optimisticValue; } ); startTransition(async () => { addOptimistic(1); const newLikes = await api.postLike(); setLikes(newLikes); }); likes = 10 optimisticValue = 1 ① 非同期トランジション開始 → addOptimistic呼び出し dispLikes = 10 + 1 = 11 ⇒
useOptimisticの動作例 const [likes, setLikes] = useState(0); const [dispLikes, addOptimistic] =
useOptimistic( likes, (currentLikes, optimisticValue) => { return currentLikes + optimisticValue; } ); startTransition(async () => { addOptimistic(1); const newLikes = await api.postLike(); setLikes(newLikes); }); likes = 11 ② ステート更新して トランジション終了 (楽観的更新状態ではなくなる) dispLikes = 11 ⇒
useOptimisticまとめ アクションの中で addOptimisticを呼び出すことで 楽観的更新を行う。 「アクションの実行中は楽観的更新の内容が表示される」 「アクションが完了したら自動的に元に戻る」 というシンプルな挙動であり、 アクションの概念を理解した人にとっては分かりやすい。
useOptimistic補足 Q. なぜ楽観的更新後の値を直接指定するのではなく関数を 介するのか? const [likes, setLikes] = useState(0); const
[dispLikes, addOptimistic] = useOptimistic( likes, (currentLikes, optimisticValue) => { return currentLikes + optimisticValue; } );
useOptimistic補足 Q. なぜ楽観的更新後の値を直接指定するのではなく関数を 介するのか? A. 元の値が変化した場合や複数トランジションが走って いる場合にも対応するため
useActionState
useActionStateの概要 新しいステートを宣言するフック。 ステートの初期値と、 ステートを更新するためのアクションを受け取る。 ある意味useReducerに近い点もあるフック。
useActionStateの使い方(宣言側) const [state, runAction, isPending] = useActionState(async () => {
const result = await api.postLike(); return result; }, null, ); ステートを保持 ステートの初期値 アクションの返り値でステート更新
useActionStateの使い方(呼び出し側) const [state, runAction, isPending] = useActionState(async () => {
… }, null); … <button type=“button” onClick={runAction} /> useActionStateから返ってきた関数を 呼び出せばアクションが実行される
useActionStateとトランジション const [state, runAction, isPending] = useActionState(async () => {
… }, null); useActionStateから得られたrunActionを実行すると、 自動的に非同期トランジションになる。 (useActionStateにuseTransition相当の機能も 内包されている)
useActionStateまとめ useTransitionとuseStateをくっつけた 便利なフック。 あるいはuseReducerの非同期版。 これがあるので、非同期トランジションのために useTransitionを直接使うことは少ないかも。
useActionStateの追加機能 実は、連打したときにアクションが 複数並列実行されないように制御してくれる。 useReducerの非同期版と考えれば、並列実行 できないのは自然か。(Quramyさんの受け売り [1]) [1] Server Actions の同時実行制御と画面の状態更新
https://quramy.medium.com/server-actions- %E3%81%AE%E5%90%8C%E6%99%82%E5%AE%9F%E8%A1%8C%E5%88%B6%E5%BE%A1%E3%81%A8%E7% 94%BB%E9%9D%A2%E3%81%AE%E7%8A%B6%E6%85%8B%E6%9B%B4%E6%96%B0-35acf5d825ca
<form>とアクション
<form>の新機能 react-domの新機能として、<form>の action属性にアクションを渡せるようになった。 フォームが送信されると呼び出される。
<form>のactionにアクションを渡す <form action={async () => { addOptimistic(1); const newLikes =
await api.postLike(); setLikes(newLikes); }}> … </form> アクションなので useOptimisticにも対応
<form>のisPendingを取得したい アクションということはisPendingの概念があるはず。 それはuseFormStatusで取得できる。 const { isPending } = useFormStatus(); (非制御コンポーネントやサーバー関係の諸々のために
FormDataを取得できる機能もある) <form>の中のコンポーネント で呼び出す必要がある
useActionStateとの組み合わせ <form>の外から状態を管理したい場合に有効。 const [state, runAction, isPending] = useActionState(async () =>
{ … }, null); <form action={runAction}>…</form>
Server Actionsとの関係は?
Server ActionsとActionsの関係 Q. ここまで見てきたアクションと、Next.jsとかで出て くるServer Actionsの関係は?
Server ActionsとActionsの関係 Q. ここまで見てきたアクションと、Next.jsとかで出て くるServer Actionsの関係は? A. Server Actionsはクライアントから見たら非同期関数。 非同期関数はだいたいアクションである。
使う側から見れば、Server Actionsはアクションの一種。
Server Actionsに関係するAPI <form>のactionやuseActionStateは、 Server Actionsと特に深い関係にある。 今回はサーバー周りまで踏み込む時間がないので 省略。
アクション系以外の 新機能ダイジェスト
メタデータ <title>, <link>, <meta> をレンダリング するとheadに反映してくれる。便利。 <article> <h1>{post.title}</h1> <title>{post.title}</title> <link
rel=“canonical” href=“https://...” />
スタイルシート <link rel=“stylesheet”>や<style>も レンダリング可能。しかもSuspense対応。 (スタイルシートが読み込まれるまでサスペンドして コンポーネントの表示を待ってくれる) <div className=“card”> <link rel=“stylesheet”
href=“…” precedence=“default” /> …
スクリプト <script>もasync属性を付けることで サスペンド対応になる。謎のサードパーティ スクリプトを読み込む必要があるときに便利。 <div> <script async src=“nazo_gadget.js” /> <button
onClick={() => NazoGadget.start()} /> </div>
Contextを直接コンポーネントとして 使えるやつ const MyContext = createContext(); // これまで <MyContext.Provider value={…}>
// これから <MyContext value={…}>
ほか多数 他にも細かな改善がいろいろ入っていますが、 全部紹介する時間もないのでまた今度。
ほか多数 他にも細かな改善がいろいろ入っていますが、 全部紹介する時間もないのでまた今度。
None
Zenn本「React 19新機能まるわかり」 このイベント終了後に配信開始 ¥0 (税込) アクション周りの話はもちろん、 今回紹介しきれなかった React 19の新機能を全部 詰め込んだZenn本が新登場。
React 19へのアップグレード
React 19の破壊的変更 メジャーバージョンアップなので破壊的変更がある。 内容的に、破壊力は控えめの印象。
古い機能の削除 すでに非推奨化済の古い機能がいろいろ削除される。 5年以上メンテされていないコードや外部ライブラリ がある人は要注意。 • 関数コンポーネントのdefaultProps • Legacy Context •
String refs • など
TypeScript型定義の破壊的変更 こちらのほうが破壊力高いが、ランタイムの変更 ではないのでまだマシ。 const myRef = useRef<HTMLDivElement>(); React.MutableRef<HTMLDivElement> const [state,
dispatch] = useReducer<FuncType>(); 引数の無いuseRefは不可になった MutableRefという型はAPIで 使われなくなり、非推奨になった useReducerの型引数は 破壊的変更が入った
まとめ
まとめ React 19で新しく登場したAPIたちは、 アクションという新概念でまとめられている。 (今回省略したuseはまた別) Suspenseやトランジションという既存概念を 土台にアクションを理解することが React 19を使いこなす近道となる。