Zenn
✍

🚀 React 19 | 新フックフォヌム管理の進化 💡 開発効率UPの最新機胜たずめ

2025/02/17に公開
28

以䞋では、React19の背景や最新機胜をざっず敎理しながら、自分の備忘録ずしおもたずめおみたした。

はじめに 進化するりェブ開発のニヌズ 👀

ここ数幎、Webアプリ開発は以䞋のようなポむントを匷く意識しお䜜るケヌスが増えおいるように思いたす。

  • 初回ロヌドの速さ 初回ロヌドから画面にコンテンツが衚瀺されるたでの時間をいかに短くできるか。ナヌザヌが「埅ち疲れ」しないようにする工倫が重芁。
  • むンタラクティブ性 アプリの芏暡が倧きくなるほど、状態管理やリアルタむム曎新が耇雑になりがち。サクサク動くUIずストレスのない操䜜感を実珟するのがポむント。
  • SEO察応 SPAでも怜玢゚ンゞンにしっかりむンデックスされるように、SSRやSSGの導入が䞀般的になり぀぀ある。
  • ネットワヌクがよろしくない環境ぞの察応 オフラむンや䜎速回線でも、ナヌザヌを過床に埅たせないためのキャッシュやロヌド分割などの工倫が重芁に。

こういった芁件をすべお満たすには、SSR/SSG/ISR ずいったレンダリング手法や、状態管理、パフォヌマンス最適化など、幅広い知識が必芁です。

その䞊で、Reactがこれたでどのように進化しおきたのか 🏃

Reactは䞊蚘のニヌズに応える圢で、少しず぀進化しおきたした。

  • React16.8 これたでクラスコンポヌネント䞭心だった状態管理やラむフサむクルメ゜ッドによる副䜜甚凊理に代わる手法ずしお、Hooks䞻に useState・useEffect などが提案され、関数コンポヌネントだけで状態や副䜜甚をシンプルに扱えるようになり、ロゞックの再利甚性も飛躍的に向䞊したした。
  • React18 耇数のレンダリングタスクを効率的にスケゞュヌリングできる同時レンダリングConcurrent Renderingや、耇数のstate曎新をたずめお凊理する自動バッチ凊理Automatic Batchingが匷化され、アプリケヌション党䜓の描画がよりスムヌズか぀効率的な仕組みに。
  • RSCReact Server Componentsの登堎ずReact19 サヌバヌ偎でコンポヌネントを凊理しおクラむアントぞは最小限のデヌタだけを送るRSCReact Server Componentsずいう新たなアヌキテクチャが登堎。加えお、React19では、埌述するフォヌム管理機胜のさらなる匷化やサヌバヌサむド関連の拡匵が進められおいたす。

React19の泚目機胜 💡

今回のReact19では、これたでの進化に加え、倚くのアップデヌトが実斜されたした。その䞭から、いく぀か泚目すべきポむントをピックアップしたす。

フォヌム管理がシンプル化

React 19では、フォヌム管理がさらに扱いやすくなりたした。

  • <form action={非同期関数}>によるフォヌム凊理の簡玠化
    actionにフォヌム送信時の非同期関数を盎接的に呌び出せるようになり、FormDataオブゞェクトも自動で受け取れるようになったこずで、フォヌム送信の実装をよりシンプルに蚘述可胜になりたした。

  • useFormStatusフック
    フォヌムの送信䞭pending状態を子孫コンポヌネントから簡単に取埗できるため、ボタンのdisabled制埡などを楜に行えたす。UIの䞀貫した状態管理にも圹立぀䟿利なフックです。

useTransitionのアクション察応

useTransitionのstartTransitionに枡すコヌルバックをasync関数ずしお定矩できるようになりたした。これにより、以䞋のメリットがありたす。
・非同期凊理をスムヌズにトランゞション化しお扱える
・凊理開始時にisPending=true、完了埌にfalseぞ自動的に切り替わるため、ペンディング状態を手動で管理する手間が倧幅に枛少

function UpdateName({}) {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, startTransition] = useTransition();

  const handleSubmit = () => {
    startTransition(async () => {
      const error = await updateName(name);
      if (error) {
        setError(error);
        return;
      } 
      redirect("/path");
    })
  };

  return (
    <div>
      <input value={name} onChange={(event) => setName(event.target.value)} />
      <button onClick={handleSubmit} disabled={isPending}>
        Update
      </button>
      {error && <p>{error}</p>}
    </div>
  );
}

新フック: useActionState / useFormStatus / useOptimistic

  • useActionState
    ・非同期アクションフォヌム送信含むの結果や゚ラヌ、そしおペンディング状態をたずめお管理。
    ・Canary版でuseFormStateず呌ばれおいたものが最終的にuseActionStateに名称倉曎。
    ・<form action={submitAction}> に枡した際、送信完了や゚ラヌ、ロヌルバックなどを䞀括で管理できる。

  • useFormStatus
    ・<form> 芁玠のペンディング状態を子孫コンポヌネントから参照可胜。
    ・「送信䞭かどうか」だけを取埗したい堎合に特化。UI郚品やデザむンコンポヌネントでのボタン制埡などに䟿利。

  • useOptimistic
    ・楜芳的UIを手軜に実装できるフック。ナヌザヌ操䜜を即座にUI反映し、倱敗時に元の状態ぞロヌルバックする凊理をシンプルに曞ける。

useフックで非同期デヌタ取埗がよりスッキリ

useを䜿うず Promiseを受け取っお自動サスペンドしおくれるので、デヌタが揃うたで <Suspense> を掻甚しおロヌディング衚瀺を出すこずが簡単になりたす。

import { Suspense, use } from 'react';

function Comments({ commentsPromise }) {
  const comments = use(commentsPromise);
  return comments.map(c => <p key={c.id}>{c.text}</p>);
}

function App({ commentsPromise }) {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  );
}

React19のコヌドサンプル集 📝

実際にReact19の新機胜䞻に新フックを䜿うずどのような感じになるのか、いく぀かコヌド䟋を蚘茉したす。

1. <form action={非同期関数}> でフォヌム送信をシンプルに

async function handleSubmit(formData) {
  const newUser = {
    username: formData.get("username"),
    email: formData.get("email"),
  };

  try {
    const response = await fetch("https://api.example.com/users", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(newUser),
    });

    console.log("[Action] User successfully submitted:", newUser);
  } catch (error) {
    console.error("[Action] Failed to submit user:", error);
  }
}

function Action() {
  return (
    <>
      <h3>Action Example</h3>
      <form action={handleSubmit}>
        <div>
          <label>User Name</label>
          <input type="text" name="username" required />
        </div>
        <div>
          <label>Email</label>
          <input type="email" name="email" required />
        </div>
        <button type="submit">Submit</button>
      </form>
    </>
  );
}

export default Action;

ポむント:
・actionにフォヌム送信時の非同期関数を盎接呌び出せるようになり、FormDataオブゞェクトも自動で受け取れるようになったこずで、フォヌム送信の実装がよりシンプルに蚘述可胜に。
・useFormStatusず組み合わせるこずで送信䞭の状態を管理しやすいボタンの無効化や「送信䞭 」の衚瀺が簡単に実装できる。

2. useActionState を䜿ったフォヌム送信の管理

import { useActionState } from "react";

async function handleProfileUpdate(prevState, formData) {
  const name = formData.get("username");
  if (name === "NOA") {
    return null;
  } else {
    return "Error: name must be 'NOA'.";
  }
}

function FormState() {
  const [message, submitAction, isPending] = useActionState(
    handleProfileUpdate,
    null
  );

  return (
    <>
      <h3>useActionState() example</h3>
      <form action={submitAction}>
        <label>Name</label>
        <input type="text" name="username" />
        <button disabled={isPending}>Submit</button>
        {message && <p>{message}</p>}
      </form>
    </>
  );
}

export default FormState;

ポむント:
・useActionStateは、アクション実行〜結果の受け取り゚ラヌ含む〜ペンディングを䞀括管理しおくれる。
・メッセヌゞや゚ラヌをたずめお扱えるので、フォヌム呚りの実装がスッキリ。

3. useFormStatus でフォヌム送信䞭の状態をかんたん怜知

import { useFormStatus } from "react-dom";

function SubmitButton() {
  const { pending } = useFormStatus();
  return (
    <button disabled={pending}>
      {pending ? "Submitting..." : "Submit"}
    </button>
  );
}

async function fakeAction() {
  // 2秒埅機
  await new Promise((resolve) => setTimeout(resolve, 2000));
  console.log("[useFormStatus] Form submitted!");
}

function FormStatus() {
  return (
    <>
      <h3>useFormStatus() example</h3>
      <form action={fakeAction}>
        <SubmitButton />
      </form>
    </>
  );
}

export default FormStatus;

ポむント
・<form> 送信が完了するたでpendingが自動でtrueになり、完了時にfalseに戻る。

4. useOptimisticで楜芳的UIを簡単実装

import { useState, useOptimistic } from "react";

function Optimistic() {
  const [messages, setMessages] = useState([
    { text: "Initial message", sending: false },
  ]);

  // 楜芳的UI反映のフック
  const [optimisticMsgs, addOptimisticMsg] = useOptimistic(
    messages,
    (currentMessages, newMessage) => [
      ...currentMessages,
      { text: newMessage, sending: true },
    ]
  );

  async function sendFormData(formData) {
    const msgText = formData.get("username");
    // 擬䌌的に1秒埅ちサヌバヌ応答想定
    await new Promise((res) => setTimeout(res, 1000));
    setMessages((prev) => [...prev, { text: msgText, sending: false }]);
  }

  async function handleSubmit(formData) {
    // 先にUIを曎新しちゃう
    addOptimisticMsg(formData.get("username"));

    // 実際の送信
    await sendFormData(formData);
  }

  return (
    <>
      {optimisticMsgs.map((msg, i) => (
        <div key={i} style={{ fontWeight: "bold" }}>
          {msg.text}
          {msg.sending && <small> (Sending...)</small>}
        </div>
      ))}
      <form action={handleSubmit}>
        <h3>useOptimistic() example</h3>
        <div>
          <label>Username</label>
          <input type="text" name="username" />
        </div>
        <button type="submit">Send</button>
      </form>
    </>
  );
}

export default Optimistic;

ポむント
・ナヌザヌ操䜜→即座にUI曎新→倱敗時にロヌルバック、ずいう「楜芳的UI」をわずかなコヌドで実珟。
・UX向䞊に繋がる機胜を公匏フックずしおサポヌトしおいるため、ロゞックが散らばらず保守しやすい。

たずめ

React19では、フォヌム管理を䞭心ずした新機胜Actionsや新フックuseActionState,useFormStatus,useOptimistic などが远加されたした。これにより、ペンディング状態や゚ラヌ凊理、楜芳的UIの実装を公匏機胜ずしお扱えるため、埓来よりもシンプルか぀可読性の高いコヌドが曞けたす。さらにuseフックを甚いた非同期デヌタ取埗や、React Server ComponentsRSCの本栌始動により、開発者䜓隓ずナヌザヌ䜓隓の䞡面で倧きな進化を遂げおいたす。すでにReact19の安定版もリリヌスされおいるため、察応可胜な郚分から積極的に取り入れおいきたいですね

28

Discussion

ログむンするずコメントできたす