当前位置: 首页 > article >正文

react中hooks之 React 19 新 Hooks useActionState useFormStatus用法总结

React 19 新 Hooks 使用指南: useActionState & useFormStatus

目录

  1. useActionState
  2. useFormStatus
  3. 最佳实践

useActionState

概述

useActionState 是 React 19 引入的新 Hook,用于处理表单 action 的状态更新。它允许你基于表单 action 的结果来更新组件状态。
官网:

基本语法

const [state, formAction, isPending] = useActionState(fn, initialState, permalink?);

参数说明

  1. fn: 表单提交时调用的函数

    • 接收上一次状态作为第一个参数
    • 接收表单数据作为后续参数
    • 返回新的状态
  2. initialState: 初始状态值

    • 可以是任何可序列化的值
    • 在 action 首次调用后会被忽略
  3. permalink?: (可选) 唯一页面 URL

    • 用于动态内容页面(如 feeds)
    • 配合渐进式增强使用
    • 在 JavaScript bundle 加载前提交表单时使用

返回值

type UseActionStateReturn<T> = [
  T,                    // 当前状态
  (formData: FormData) => void,  // 表单 action
  boolean               // 是否处于 pending 状态
];

使用示例

async function increment(previousState: number, formData: FormData) {
  return previousState + 1;
}

function Counter() {
  const [count, formAction, isPending] = useActionState(increment, 0);
  
  return (
    <form>
      <p>Count: {count}</p>
      <button formAction={formAction} disabled={isPending}>
        {isPending ? 'Incrementing...' : 'Increment'}
      </button>
    </form>
  );
}

useFormStatus

概述

useFormStatus 是一个专门用于获取父级表单提交状态的 Hook。它提供了表单提交过程中的详细状态信息。

基本语法

const { pending, data, method, action } = useFormStatus();

使用限制

  1. 必须在 <form> 元素内部使用
  2. 必须是表单的子组件
  3. 不能在表单 action 处理函数内使用

使用示例

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

function Form() {
  async function formAction(formData: FormData) {
    // 处理表单提交
  }

  return (
    <form action={formAction}>
      <input name="name" />
      <SubmitButton />
    </form>
  );
}

最佳实践

  1. Server Actions 集成
// 服务端 action
async function updateUser(prevState: any, formData: FormData) {
  'use server';
  const name = formData.get('name');
  await db.updateUser({ name });
  return { message: 'Updated!' };
}

// 客户端组件
function UserForm() {
  const [state, formAction] = useActionState(updateUser, null);
  return (
    <form action={formAction}>
      <input name="name" />
      <SubmitButton />
      {state?.message && <p>{state.message}</p>}
    </form>
  );
}
  1. 错误处理
async function submitForm(prevState: any, formData: FormData) {
  try {
    const result = await submitData(formData);
    return { data: result, error: null };
  } catch (e) {
    return { data: null, error: e.message };
  }
}
  1. 渐进式增强
function CommentForm({ postId }) {
  const [state, formAction] = useActionState(
    submitComment,
    null,
    `/posts/${postId}#comments` // permalink for progressive enhancement
  );
  
  return (
    <form action={formAction}>
      {/* 表单内容 */}
    </form>
  );
}

注意事项

  1. useActionState:

    • 与框架的 Server Components 集成时支持服务端渲染
    • 函数签名与直接使用表单 action 不同
    • 支持渐进式增强
  2. useFormStatus:

    • 只能在表单子组件中使用
    • 提供实时的表单状态
    • 适合构建可复用的表单组件
  3. 性能考虑:

    • 自动处理并发更新
    • 支持 Suspense 集成
    • 优化服务端状态同步

最佳实践补充

  1. 状态复用
// 创建可复用的表单状态 hook
function useFormWithStatus<T>(action: string) {
  const formStatus = useFormStatus();
  const [formState, setFormState] = useState<T | null>(null);

  useEffect(() => {
    if (!formStatus.pending && formStatus.data) {
      setFormState(Object.fromEntries(formStatus.data.entries()) as T);
    }
  }, [formStatus.pending, formStatus.data]);

  return {
    ...formStatus,
    formState
  };
}
  1. 类型安全处理
// 为 useActionState 添加类型
interface UserData {
  id: string;
  name: string;
  email: string;
}

const [updateUser, { data }] = useActionState<UserData, Partial<UserData>>(
  async (updates) => {
    const response = await fetch('/api/user', {
      method: 'PATCH',
      body: JSON.stringify(updates)
    });
    return response.json();
  }
);

// TypeScript 会正确推断 data 的类型为 UserData | null

总结

  1. useActionState 优点:

    • 简化异步状态管理
    • 提供完整的状态信息
    • 易于集成错误处理
    • 支持类型安全
  2. useFormStatus 优点:

    • 专注于表单状态
    • 提供详细的提交信息
    • 易于实现加载指示器
    • 支持复杂表单流程
  3. 使用建议:

    • 合理区分两个 Hook 的使用场景
    • 实现适当的加载状态展示
    • 做好错误处理
    • 考虑状态持久化需求

http://www.kler.cn/a/514164.html

相关文章:

  • python学opencv|读取图像(四十)掩模:三通道图像的局部覆盖
  • react install
  • 【Vim Masterclass 笔记22】S09L40 + L41:同步练习11:Vim 的配置与 vimrc 文件的相关操作(含点评课内容)
  • Golang Gin系列-4:Gin Framework入门教程
  • 用edge浏览器追剧音量太小?安装音量增强器可解忧
  • QT 占位符的用法
  • js重要知识点
  • MySQL入门(数据库、数据表、数据、字段的操作以及查询相关sql语法)
  • SQL中字符串截取函数(substring)
  • 解决 PostgreSQL 中创建 TimescaleDB 扩展的字符串错误
  • 分布式系统架构8:分布式缓存
  • SpringMVC新版本踩坑[已解决]
  • 2025年01月20日Github流行趋势
  • 连接 OpenAI 模型:基础操作
  • LatentSync本地部署教程:基于音频精准生成唇形高度同步视频
  • C#与AI的共同发展
  • list底层实现细节
  • 数据清洗新利器:自动化数据清洗工具的探秘
  • 我在广州学Mysql 系列——触发器的使用
  • AG32 FPGA 的 Block RAM 资源:M9K 使用
  • Go语言如何实现限制用户 1 分钟内最多请求 1000 次?
  • PHP礼品兑换系统小程序
  • 【漫话机器学习系列】054.极值(Extrema)
  • 接口(1)
  • 苍穹外卖项目总结(二)
  • MyBatis Plus 的 InnerInterceptor:更轻量级的 SQL 拦截器