React 19 Hooks 进阶:useOptimistic 与 useActionState 实战

2 阅读1分钟

目录 (Outline)


一、 交互体验的进化:为什么我们需要乐观更新?

在传统的 Web 开发中,当用户执行一个写操作(如点赞、发评论)时,流程通常是:

  1. 用户点击按钮。
  2. 显示 Loading 状态。
  3. 等待后端接口返回(可能需要 500ms~2s)。
  4. 更新 UI。

这种「先等再更」的模式在弱网环境下会让应用显得非常迟钝。而 乐观更新 (Optimistic Updates) 的核心思想是:假设操作一定会成功,先立即更新 UI,同时在后台发送请求;如果请求失败,再回滚 UI。


二、 useOptimistic 深度解析:原理与核心用法

useOptimistic 是 React 19 专门为乐观更新设计的官方 Hook。它能确保乐观状态在异步操作期间存在,并在操作结束后自动恢复到真实状态。

1. 核心 API

const [optimisticState, addOptimistic] = useOptimistic(
  state, // 真实的初始状态
  (currentState, optimisticValue) => {
    // 状态合并逻辑
    return [...currentState, optimisticValue];
  }
);

2. 为什么它比手动维护状态好?

  • 自动同步:一旦主状态更新,乐观状态会自动基于主状态重新计算。
  • 并发友好:它与 React 的 Transition 机制深度绑定,不会阻塞其他渲染。

三、 useActionState 实战:表单异步状态的自动管理

在 React 19 之前,我们需要手动维护 isLoading, error 等状态。useActionState 让这一切成为了过去。

实战代码

import { useActionState } from 'react';

async function submitAction(prevState, formData) {
  try {
    const res = await api.updateName(formData.get('name'));
    return { success: true, name: res.name };
  } catch (e) {
    return { error: '更新失败,请重试' };
  }
}

function ProfileForm() {
  const [state, formAction, isPending] = useActionState(submitAction, { name: '' });

  return (
    <form action={formAction}>
      <input name="name" disabled={isPending} />
      <button type="submit" disabled={isPending}>
        {isPending ? '保存中...' : '保存'}
      </button>
      {state.error && <p className="error">{state.error}</p>}
    </form>
  );
}

四、 黄金组合实战:构建一个「秒回」的消息评论系统

我们将 useOptimisticuseActionState 结合,实现一个完美的评论功能。

完整代码示例

import { useOptimistic, useActionState, useTransition } from 'react';

function CommentSection({ initialComments }) {
  // 1. 定义乐观更新状态
  const [optimisticComments, addOptimisticComment] = useOptimistic(
    initialComments,
    (state, newComment) => [...state, { text: newComment, sending: true }]
  );

  // 2. 定义异步 Action
  async function addCommentAction(prevState, formData) {
    const text = formData.get('comment');
    
    // 立即触发乐观更新
    addOptimisticComment(text);
    
    try {
      await api.postComment(text); // 真实的后台请求
      return { success: true };
    } catch (e) {
      return { error: '评论发送失败' };
    }
  }

  const [state, formAction] = useActionState(addCommentAction, null);

  return (
    <div>
      {/* 渲染乐观状态的列表 */}
      {optimisticComments.map((c, i) => (
        <div key={i} style={{ opacity: c.sending ? 0.5 : 1 }}>
          {c.text} {c.sending && '(发送中...)'}
        </div>
      ))}

      <form action={formAction}>
        <input name="comment" placeholder="说点什么..." />
        <button type="submit">发送</button>
      </form>
      
      {state?.error && <p style={{ color: 'red' }}>{state.error}</p>}
    </div>
  );
}

五、 总结与最佳实践

  • 配合 TransitionuseOptimistic 必须在 TransitionAction 内部调用。
  • 回滚机制:开发者无需手动写回滚代码,React 会在异步 Action 结束后,自动丢弃乐观状态,切换回真实的 initialComments
  • 建议:新项目应全面弃用手动的 setLoading(true),改用 useActionState + useOptimistic 的组合。

这两个 Hooks 的出现,标志着 React 已经从一个单纯的 UI 库,进化成为了一个深度理解「用户交互心理」的智能框架。