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
22
9.7k
React 19を概念から理解する
2024-05-29うひょさんに聞く! React 19アップデートの勘所
#React19_Findy
uhyo
May 28, 2024
Tweet
Share
More Decks by uhyo
See All by uhyo
TypeScriptの次なる大進化なるか!? 条件型を返り値とする関数の型推論
uhyo
2
1.6k
tsconfig.jsonの最近の新機能 ファイルパス編
uhyo
7
2.2k
非同期処理を活用しながらRust製wasmとJSを連携する方法(wasm-bindgenを使いたくない人向け)
uhyo
4
3.7k
tsconfig.jsonの設定を見直そう!フロントエンド向け 2024夏
uhyo
26
8.8k
require(ESM)とECMAScript仕様
uhyo
6
1.9k
TypeScript Quiz (Encraft #12 Frontend Quiz Night)
uhyo
8
1.7k
Shadow DOMとCSSの現状
uhyo
11
7.3k
TypeScriptってどんな言語? 言語そのものを知る面白さ
uhyo
16
8.9k
App Router時代のデータ取得アーキテクチャ
uhyo
49
16k
Other Decks in Technology
See All in Technology
ハイパーパラメータチューニングって何をしているの
toridori_dev
0
140
AWS Media Services 最新サービスアップデート 2024
eijikominami
0
190
Why App Signing Matters for Your Android Apps - Android Bangkok Conference 2024
akexorcist
0
120
信頼性に挑む中で拡張できる・得られる1人のスキルセットとは?
ken5scal
2
530
ドメイン名の終活について - JPAAWG 7th -
mikit
33
20k
安心してください、日本語使えますよ―Ubuntu日本語Remix提供休止に寄せて― 2024-11-17
nobutomurata
0
980
社内で最大の技術的負債のリファクタリングに取り組んだお話し
kidooonn
1
550
Lambda10周年!Lambdaは何をもたらしたか
smt7174
2
110
VideoMamba: State Space Model for Efficient Video Understanding
chou500
0
190
Amplify Gen2 Deep Dive / バックエンドの型をいかにしてフロントエンドへ伝えるか #TSKaigi #TSKaigiKansai #AWSAmplifyJP
tacck
PRO
0
370
AGIについてChatGPTに聞いてみた
blueb
0
130
rootlessコンテナのすゝめ - 研究室サーバーでもできる安全なコンテナ管理
kitsuya0828
3
380
Featured
See All Featured
Build your cross-platform service in a week with App Engine
jlugia
229
18k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
5 minutes of I Can Smell Your CMS
philhawksworth
202
19k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
42
9.2k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
126
18k
GraphQLの誤解/rethinking-graphql
sonatard
67
10k
Optimizing for Happiness
mojombo
376
70k
StorybookのUI Testing Handbookを読んだ
zakiyama
27
5.3k
Building an army of robots
kneath
302
43k
Designing on Purpose - Digital PM Summit 2013
jponch
115
7k
Why Our Code Smells
bkeepers
PRO
334
57k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
665
120k
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を使いこなす近道となる。