Quiet
  • 主页
  • 归档
  • 分类
  • 标签
  • 链接
  • 关于我

bajiu

  • 主页
  • 归档
  • 分类
  • 标签
  • 链接
  • 关于我
Quiet主题
  • React

React 19 新特性

bajiu
前端

2025-06-03 10:47:00

React 版本中文API: https://zh-hans.react.dev/versions

纯血文档: https://react.dev/blog/2024/12/05/react-19

React 19 的核心更新

1. 内置的“Actions”支持(用于表单和数据处理

异步数据更新一直是 React 应用中的难点之一。React 19 引入了 Actions,通过支持异步函数来管理数据变更、加载状态、错误处理和乐观更新(optimistic updates),使复杂逻辑的处理变得更加简单。

  • 新增 <form action={someFunction}> 的支持,让表单处理变得和原生一样直观。
  • 类似于 Remix 中的功能:你可以直接将一个 JS 函数作为 action 传入。
  • React 会自动处理表单提交、状态、刷新逻辑

在 React 19 中,可以将表单直接提交到一个函数(action),而不需要再写 onSubmit + preventDefault + fetch 那些繁琐逻辑。

传统表单写法(React 18 及之前)

function App() {
  const [name, setName] = useState('');

  function handleSubmit(e) {
    e.preventDefault(); // 阻止默认行为
    fetch('/api/save', {
      method: 'POST',
      body: JSON.stringify({ name })
    });
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <button type="submit">提交</button>
    </form>
  );
}

React 19 新写法:直接绑定 action 函数

function App() {
  async function saveName(formData) {
    const name = formData.get('name');
    await fetch('/api/save', {
      method: 'POST',
      body: JSON.stringify({ name }),
    });
  }

  return (
    <form action={saveName}>
      <input name="name" placeholder="输入名字" />
      <button type="submit">提交</button>
    </form>
  );
}

变化点:

  • 不需要 e.preventDefault();
  • 不需要 useState 控制 input;
  • 表单的 action 属性就是 JS 函数;
  • 参数是 FormData,与原生行为一致;
  • 内置与 useFormStatus、useFormState 联动;

2. 新的 useOptimistic Hook

useOptimistic 是 React 19 新增的一个 hook,专门用来处理“乐观更新”的场景。

useOptimistic 让你在还没收到服务器响应时,先“假装”数据已经更新,从而让用户界面更流畅。

举个粒子

社交平台点了一个“点赞”按钮,正常流程为 点击按钮 -> 发送请求 -> 等服务器确认点赞成 -> UI 显示点赞状态, 但这个过程会有延迟,感觉卡了一下。

用 useOptimistic 的方式
可以在点击后 立即更新界面 -> 显示已经点赞 -> 后台慢慢发请求 -> 请求成功后再真正更新本地状态(防止出错), 就更丝滑了。

代码对比

没有 useOptimistic

const [likes, setLikes] = useState(0);

async function handleLike() {
  const res = await fetch('/api/like'); // 等很久
  const newLikes = await res.json();
  setLikes(newLikes);
}

使用 useOptimistic 立即让用户看到结果

const [likes, setLikes] = useState(0);
const [optimisticLikes, addOptimisticLike] = useOptimistic(likes, (prev, delta) => prev + delta);

async function handleLike() {
  addOptimisticLike(1); // 立刻显示 +1 的结果
  const res = await fetch('/api/like');
  const confirmedLikes = await res.json();
  setLikes(confirmedLikes); // 最终确认真实数据
}

参数解析

const [optimisticValue, addOptimisticValue] = useOptimistic(
  baseValue,         // 初始真实值
  updateFunction     // 如何从 baseValue 推出新值
);

可以不断调用 addOptimisticValue(data) 来触发"假装"的 UI 更新。

适用场景:

  • 添加评论、点赞、发帖
  • 商品加入购物车
  • 输入框内快速反馈(如自动补全)
  • 改名/改邮箱这类提交后刷新 UI 的操作

3. 新生命周期钩子:use

React 19 引入的新生命周期钩子 use(), 让我们可以在组件内部直接”等待”异步数据或资源,不再需要复杂的 useEffect + useState 或手动管理状态。

举粒说明

直接等待数据

// App.jsx
import React, { Suspense, use } from 'react';

// 模拟异步数据请求
function fetchUser() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        name: '三三',
        age: 28,
        email: 'zhangsan@example.com',
      });
    }, 2000); // 模拟2秒延迟
  });
}

// 组件:使用 use() 等待数据
function UserInfo() {
  const user = use(fetchUser()); // use 会挂起直到 Promise resolve

  return (
    <div>
      <h2>用户信息</h2>
      <p>姓名:{user.name}</p>
      <p>年龄:{user.age}</p>
      <p>邮箱:{user.email}</p>
    </div>
  );
}

// 包装 Suspense 来处理挂起时的 fallback UI
export default function App() {
  return (
    <div>
      <h1>欢迎来到用户中心</h1>
      <Suspense fallback={<p>加载用户信息中...</p>}>
        <UserInfo />
      </Suspense>
    </div>
  );
}

不需要 useEffect、不需要状态管理,更像是同步代码那样读取数据,但底层是自动 Suspense

要点:

  • use(fetchUser()) 会自动挂起,直到 Promise 完成;
  • 外层需要用 <Suspense fallback={...}> 包裹;
  • 更适合 Server Components 或客户端 Suspense 流程;
  • 适合在组件内部加载一次数据的情况。

4. 新生命周期钩子:use

Transitions 是一种标记 非紧急更新 的方式,比如:搜索输入、分页切换、排序、筛选等不会马上影响用户操作的 UI 更新。

为什么需要 Transitions

在 React 中,所有状态更新默认是同步、高优先级的。但有些更新其实不需要立即完成,比如:

  • 筛选列表
  • 搜索输入结果展示
  • 标签页切换
  • 加载大量内容的视图切换
    如果它们不被降级,就会和输入焦点、按钮点击抢资源,造成卡顿、掉帧、响应慢的问题。

React 提供了一个内置 API:

import { startTransition } from 'react';

startTransition(() => {
  // 非紧急更新:如重新渲染大表格、更新搜索结果等
  setState(...);
});

举例说明

import React, { useState, useTransition } from 'react';

const bigList = Array.from({ length: 10000 }, (_, i) => `项目 ${i + 1}`);

export default function App() {
  const [input, setInput] = useState('');
  const [list, setList] = useState(bigList);
  const [isPending, startTransition] = useTransition();

  const handleChange = (e) => {
    const value = e.target.value;
    setInput(value); // 紧急更新,立即显示输入内容

    // 非紧急更新:过滤数据
    startTransition(() => {
      const filtered = bigList.filter(item => item.includes(value));
      setList(filtered);
    });
  };

  return (
    <div style={{ padding: '1rem' }}>
      <h2>搜索列表(共 {bigList.length} 项)</h2>
      <input
        type="text"
        value={input}
        onChange={handleChange}
        placeholder="输入关键字..."
        style={{ padding: '0.5rem', width: '300px' }}
      />
      {isPending && <p>筛选中,请稍候...</p>}
      <ul>
        {list.slice(0, 100).map((item, index) => (
          <li key={index}>{item}</li> // 只渲染前 100 项避免卡顿
        ))}
      </ul>
    </div>
  );
}

为什么 useTransition 更好

一个栗子:

const handleChange = (e) => {
  setInput(e.target.value);       // 用户输入,UI立即更新
  setFilteredList(bigList.filter(...)); // 同步过滤大列表 → 可能很慢
};

当快速打字时:

  • setFilteredList 会触发列表重渲染;
  • 渲染一万个
  • 可能非常慢;
  • 键盘输入会卡顿、掉帧,造成很差的用户体验。

改进方式:

const [isPending, startTransition] = useTransition();

const handleChange = (e) => {
  setInput(e.target.value); // 仍然是高优先级,立即响应

  startTransition(() => {
    setFilteredList(bigList.filter(...)); // 降级,等闲了再渲染
  });
};

使用 startTransition():

  • 先快速显示用户输入;
  • 然后低优先级处理列表渲染;
  • React 会在浏览器空闲时处理这部分 UI 更新;
  • 页面不卡顿,用户感觉丝滑!

那小伙伴们一定有这样的疑问,这玩意和·有什么区别呢,其实 React 的 useTransition() ≠ debounce/throttle,它们的目标和实现机制是完全不同的。可以对比理解:

  • debounce/throttle:控制函数多久执行一次,防止太频繁调用。
  • useTransition:告诉 React 哪些更新可以“等一下再做”,保证页面不掉帧不卡顿。

所以最好的实践往往是两者结合

// 节流输入触发次数
const handleInput = debounce((value) => {
  setInput(value);
  startTransition(() => {
    setFilteredList(filterBigList(value));
  });
}, 300);

这样既避免频繁触发函数,也让 React 渲染流畅不卡。

5. 原生支持 Document Metadata

React 19 原生支持 <title>、<meta> 和 <link> 等文档元数据标签。这些标签可直接在组件中声明,React 会自动将它们提升至 <head>,并确保与服务端渲染和客户端渲染兼容。

这样可以直接 简化 SEO 和元数据管理逻辑,并且不需要像以前一样手动插入标签了

function BlogPost({ post }) {
  return (
    <article>
      <h1>{post.title}</h1>
      <title>{post.title}</title>
      <meta name="author" content={post.author} />
    </article>
  );
}

剩下的感觉没那么重要,看文档吧~

上一篇

CNN简介

下一篇

ONNX简介

©2025 By bajiu.