首页
Preview

深入解读 React 19 新增 Hooks:useActionState、useFormStatus 与 useOptimistic

前言

React19发布也有一段时间了,其中,最引人注目的便是三个新的 Hooks,它们已经稳定发布并准备好投入实际开发中。对于开发者来说,这些新功能不仅能简化代码,还能提升应用的性能和用户体验。接下来,我将详细介绍这三个新的 Hooks 及其应用场景。

  • useActionState
  • useFormStatus
  • useOptimistic

这三个 Hooks 为 React 的状态管理、表单处理和异步操作提供了更加简洁且功能强大的方式。尤其是 useActionState,它结合了 useTransitionuseReducer 的优势,能够处理复杂的异步操作和状态更新逻辑,简化了传统的实现方式,并使得状态管理更加清晰高效。

在这篇文章中,我们将深入探讨这些新 Hooks 的使用方法,结合实际的代码示例来展示它们如何简化开发过程、提高代码的可维护性和可读性,同时也会对比 React 19 之前的实现方式,帮助大家更好地理解这些新特性所带来的变化和提升。如果你想跟上 React 生态的最新进展,掌握这些新功能是非常必要的。


useActionState

useActionState是一个在需要利用操作执行结果的场景中使用的Hook。
它结合了以执行操作为目的的useTransition和以管理状态为目的的useReducer的功能。

实现示例

以前的实现方式

在React19之前,通常会使用useState等方法来实现加载状态的显示以及表单值的管理。例如:

import React, { useState, useCallback, FormEvent } from "react";

const updateName = async (name: string) => {
  return new Promise<string>((resolve) => {
    setTimeout(() => resolve(name), 3000);
  });
};

export default function UseStateDemo() {
  const [name, setName] = useState<string>("");
  const [isPending, setIsPending] = useState<boolean>(false);

  const handleSubmit = useCallback(
    async (event: FormEvent<HTMLFormElement>) => {
      event.preventDefault();

      const formData = new FormData(event.currentTarget);
      const inputName = formData.get("name") as string;

      setIsPending(true);

      const newName = await updateName(inputName);

      if (newName) {
        setName(newName);
      }

      setIsPending(false);
    },
    []
  );

  return (
    <div className="mt-10">
      <h1 className="flex justify-center text-xl">useActionState</h1>
      <form
        action={handleSubmit}
        className="space-y-4 p-6 shadow-md max-w-md mx-auto"
      >
        <div className="flex flex-col">
          <input
            type="text"
            name="name"
            className="border border-gray-300 p-2"
          />
        </div>
        <button
          type="submit"
          disabled={isPending}
          className={`w-full py-2 px-4 text-white ${
            isPending
              ? "bg-emerald-400"
              : "bg-emerald-600 hover:bg-emerald-700 focus:ring-emerald-500"
          }`}
        >
          {isPending ? "Updating..." : "Update"}
        </button>
        {isPending && <p>Loading...</p>}
        {name && <p>{name}</p>}
      </form>
    </div>
  );
}

使用useActionState的实现方式

与上面的代码相比,这种实现更加高效,非常方便!

import { useActionState } from "react";

const updateName = async (name: string) => {
  return new Promise<string>((resolve) => {
    setTimeout(() => resolve(name), 3000);
  });
};

export default function UseActionStateDemo() {
  const [name, submitAction, isPending] = useActionState(
    async (prevState: string, formData: FormData) => {
      console.log("prevState : " + prevState);
      const newName = await updateName(formData.get("name") as string);
      if (!newName) {
        return "";
      }
      return newName;
    },
    "aaa"
  );

  return (
    <div className="mt-10">
      <h1 className="flex justify-center text-xl">useActionState</h1>
      <form
        action={submitAction}
        className="space-y-4 p-6 shadow-md max-w-md mx-auto"
      >
        <div className="flex flex-col">
          <input
            type="text"
            name="name"
            className="border border-gray-300 p-2"
          />
        </div>
        <button
          type="submit"
          disabled={isPending}
          className={`w-full py-2 px-4 text-white ${
            isPending
              ? "bg-emerald-400"
              : "bg-emerald-600 hover:bg-emerald-700 focus:ring-emerald-500"
          }`}
        >
          {isPending ? "Updating..." : "Update"}
        </button>
        {isPending && <p>Loading...</p>}
        {name && <p>{name}</p>}
      </form>
    </div>
  );
}

useFormStatus

useFormStatus是一个允许在表单提交后向用户显示处理状态的Hook。

正确的实现方式

在表单内部的组件中定义useFormStatus。例如:

import { useFormStatus } from "react-dom";

function Submit() {
  const { pending } = useFormStatus();
  return (
    <button
      type="submit"
      disabled={pending}
      className="bg-blue-500 text-white py-2 px-4 rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
    >
      {pending ? "Submitting..." : "Submit"}
    </button>
  );
}

async function updateName() {
  await new Promise((resolve) => setTimeout(resolve, 3000));
}

function Form({ action }: { action: () => void }) {
  return (
    <form action={action}>
      <Submit />
    </form>
  );
}

export const UseFormStatusDemo = () => {
  return (
    <div className="mt-10 flex justify-center">
      <Form action={() => updateName()} />
    </div>
  );
};

useOptimistic

useOptimistic是一个实现乐观UI更新的Hook。乐观UI更新指的是在实际处理完成之前,提前向用户显示完成后的状态。

示例实现

输入文本后,点击提交按钮会先以红色文字显示,然后在3秒后以蓝色文字显示。

import { useOptimistic, useState } from "react";

async function updateName(name: string) {
  await new Promise((resolve) => setTimeout(resolve, 3000));
  return name;
}

export const UseOptimisticDemo = () => {
  const [name, setName] = useState("");
  const [optimisticName, setOptimisticName] = useOptimistic("");

  const submitAction = async (formData: FormData) => {
    const newName = formData.get("name") as string;
    setOptimisticName(newName);
    const updatedName = await updateName(newName);
    await setName(updatedName);
  };

  return (
    <div className="mt-10">
      <h1 className="flex justify-center font-bold text-xl">useOptimistic</h1>
      <form
        action={submitAction}
        className="space-y-4 bg-white p-6 shadow-md max-w-md mx-auto"
      >
        <div className="flex flex-col">
          <input
            type="text"
            name="name"
            className="border border-gray-300"
            disabled={"" !== optimisticName}
          />
        </div>
        <button type="submit" className="bg-blue-500 text-white py-2 px-4">
          Submit
        </button>
      </form>
      <p className="mt-4 text-center">
        Your name is:{" "}
        <span className="font-semibold text-red-500">{optimisticName}</span>
        <span className="font-semibold text-blue-500">{name}</span>
      </p>
    </div>
  );
};

总结

React19新增的Hooks都非常实用,特别是useActionState,在未来的项目中会变得非常流行,并且会成为开发者处理异步操作和状态更新的必备工具。

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(1)
收藏(0)
Hedy
大家好!我是一位前端开发工程师,拥有6年以上的前端开发经验。我熟练掌握HTML、CSS、JavaScript等语言,能够灵活运用各种前端框架,如Vue、React、Uniapp、Flutter等。我注重理论与实践相结合,能够为学员提供丰富的案例和实践项目,并以生动、易懂的语言为学员讲解前端开发的核心知识和技能。我不仅注重传授技能,更关注学员的职业发展,希望通过我的教学,帮助学员成为一名优秀的前端开发工程师。

评论(0)

添加评论