Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

React 19を概念から理解する

uhyo
May 28, 2024

React 19を概念から理解する

2024-05-29うひょさんに聞く! React 19アップデートの勘所
#React19_Findy

uhyo

May 28, 2024
Tweet

More Decks by uhyo

Other Decks in Technology

Transcript

  1. Reactのこれまで React 0.14 … 神話の時代 React 15 … クラスコンポーネント全盛期 React

    16 … フックの時代(正確には16.8から) React 17 … No New Features React 18 … Suspenseの時代
  2. React 19は何の時代になる? React 0.14 … 神話の時代 React 15 … クラスコンポーネント全盛期

    React 16 … フックの時代(正確には16.8から) React 17 … No New Features React 18 … Suspenseの時代 React 19 … Actionsの時代
  3. Actionsとは? By convention, functions that use async transitions are called

    “Actions”. 非同期トランジションを使う関数のことを、 慣例的に “Actions” と呼ぶことにします。
  4. Actionsとは? By convention, functions that use async transitions are called

    “Actions”. 非同期トランジションを使う関数のことを、 慣例的に “Actions” と呼ぶことにします。 ?
  5. Actionsとは? By convention, functions that use async transitions are called

    “Actions”. 非同期トランジションを使う関数のことを、 慣例的に “Actions” と呼ぶことにします。
  6. Suspenseとトランジションの雑な例 const [userId, setUserId] = useState(0); const userProfile = use(dataSource.getUser(userId));

    // … startTransition(() => { setUserId(123); // ステート更新したらサスペンド発生 });
  7. React 19の非同期トランジション startTransition(async () => { const result = await

    updateStuff(); setMessage( result.success ? “success!” : “ouch!” ); }); 非同期関数を渡せる (この非同期関数がアクション)
  8. React 19の非同期トランジション startTransition(async () => { const result = await

    updateStuff(); setMessage( result.success ? “success!” : “ouch!” ); }); 非同期トランジションの実行中は isPendingがtrueになる。 完了したらfalseに戻る。 もちろん、トランジション内 でステート更新できる。
  9. React 19の非同期トランジション 非同期処理の間isPendingがtrueになる点で、 非同期トランジションの挙動は、 普通のトランジション + Suspenseと同じ。 Q. どちらを使えばいいか? A.

    参照系はSuspense、更新系は非同期トランジション Suspenseは参照系向けのAPIで、更新系には向いて いなかった。非同期トランジションでそこが補完された。
  10. React 19の非同期トランジション 公式ドキュメントにも Actions automatically manage submitting data for you

    という記載があり、 非同期トランジション(アクション)が更新系の サポートを意図したAPIであることが分かる。
  11. useOptimisticの使い方(宣言側) const [likes, setLikes] = useState(0); const [dispLikes, addOptimistic] =

    useOptimistic( likes, (currentLikes, optimisticValue) => { return currentLikes + optimisticValue; } );
  12. useOptimisticの使い方(宣言側) const [likes, setLikes] = useState(0); const [dispLikes, addOptimistic] =

    useOptimistic( likes, (currentLikes, optimisticValue) => { return currentLikes + optimisticValue; } ); 元データの“楽観的更新版”のステートを宣言できる。 楽観的更新版 元データ
  13. useOptimisticの使い方(更新側) const [dispLikes, addOptimistic] = useOptimistic(…); startTransition(async () => {

    addOptimistic(1); // 楽観的更新で1を足す const newLikes = await api.postLike(); setLikes(newLikes); // 元データを更新 });
  14. useOptimisticの使い方(更新側) const [dispLikes, addOptimistic] = useOptimistic(…); startTransition(async () => {

    addOptimistic(1); // 楽観的更新で1を足す const newLikes = await api.postLike(); setLikes(newLikes); // 元データを更新 }); 非同期トランジションの中でaddOptimisticを呼び出す ことで、楽観的更新として反映される。
  15. 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 ⇒
  16. 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 ⇒
  17. useOptimistic補足 Q. なぜ楽観的更新後の値を直接指定するのではなく関数を 介するのか? const [likes, setLikes] = useState(0); const

    [dispLikes, addOptimistic] = useOptimistic( likes, (currentLikes, optimisticValue) => { return currentLikes + optimisticValue; } );
  18. useActionStateの使い方(宣言側) const [state, runAction, isPending] = useActionState(async () => {

    const result = await api.postLike(); return result; }, null, ); ステートを保持 ステートの初期値 アクションの返り値でステート更新
  19. useActionStateの使い方(呼び出し側) const [state, runAction, isPending] = useActionState(async () => {

    … }, null); … <button type=“button” onClick={runAction} /> useActionStateから返ってきた関数を 呼び出せばアクションが実行される
  20. useActionStateとトランジション const [state, runAction, isPending] = useActionState(async () => {

    … }, null); useActionStateから得られたrunActionを実行すると、 自動的に非同期トランジションになる。 (useActionStateにuseTransition相当の機能も 内包されている)
  21. <form>のactionにアクションを渡す <form action={async () => { addOptimistic(1); const newLikes =

    await api.postLike(); setLikes(newLikes); }}> … </form> アクションなので useOptimisticにも対応
  22. TypeScript型定義の破壊的変更 こちらのほうが破壊力高いが、ランタイムの変更 ではないのでまだマシ。 const myRef = useRef<HTMLDivElement>(); React.MutableRef<HTMLDivElement> const [state,

    dispatch] = useReducer<FuncType>(); 引数の無いuseRefは不可になった MutableRefという型はAPIで 使われなくなり、非推奨になった useReducerの型引数は 破壊的変更が入った