React 19 中的新特性

React 19 带来了一系列新功能,赋予了开发者更多能力。这篇文章将概述 React 19 的新特性,以及如何使用它们。

React 19 新特性介绍 🚀

异步函数的操作

React 19 引入了 Actions 功能,简化了异步请求的处理。此功能会自动管理待处理状态、错误和乐观更新。借助 useTransition,开发者现在可以更直观地处理异步操作,在数据变更时保持用户界面的响应性。

js 复制代码
// 使用 Actions 中的待定状态
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>
  );
}

简化表单处理

新的 <form> Actions 可自动处理表单提交,为了使 Actions 的常见情况更加简单,React 19 添加了一个名为 useActionState 的新 Hook,这是一个可以根据某个表单动作的结果更新 state 的 Hook。

js 复制代码
// 使用 <form> Actions 和 useActionState
function ChangeName({ name, setName }) {
  const [error, submitAction, isPending] = useActionState(async (previousState, formData) => {
    const error = await updateName(formData.get("name"));
    if (error) {
      return error;
    }
    redirect("/path");
    return null;
  }, null);

  return (
    <form action={submitAction}>
      <input type="text" name="name" />
      <button type="submit" disabled={isPending}>
        Update
      </button>
      {error && <p>{error}</p>}
    </form>
  );
}

useOptimistic 的乐观更新功能

useOptimistic Hook 使开发者能够在实际数据变更于后台执行时,即时在用户界面上呈现更新结果。该 hook 通过管理临时 UI 状态实现这一机制,若操作失败则会自动恢复至原始状态。

js 复制代码
function ChangeName({ currentName, onUpdateName }) {
  const [optimisticName, setOptimisticName] = useOptimistic(currentName);

  const submitAction = async (formData) => {
    const newName = formData.get("name");
    setOptimisticName(newName);
    const updatedName = await updateName(newName);
    onUpdateName(updatedName);
  };

  return (
    <form action={submitAction}>
      <p>Your name is: {optimisticName}</p>
      <p>
        <label>Change Name:</label>
        <input type="text" name="name" disabled={currentName !== optimisticName} />
      </p>
    </form>
  );
}

通过 useFormStatus 访问表单状态

引入 useFormStatus 钩子来直接访问表单提交的状态,这一特性非常适合用于构建需要实时反馈提交状态的组件,无需通过逐层传递属性即可实现状态同步,显著提升了组件设计的便捷性。

js 复制代码
import {useFormStatus} from 'react-dom';

function DesignButton() {
  const {pending} = useFormStatus();
  return <button type="submit" disabled={pending} />
}

全新数据读取API:use

在 React 19 中,新增了一个新的 API 用来在渲染中读取资源:use。 例如,你可以使用 use 读取一个 promise,React 将挂起,直到 promise 解析完成:

js 复制代码
import { use } from "react";

function Comments({ commentsPromise }) {
  // `use` 将被暂停直到 promise 被解决.
  const comments = use(commentsPromise);
  return comments.map((comment) => <p key={comment.id}>{comment}</p>);
}

function Page({ commentsPromise }) {
  // 当"use"在注释中暂停时,
  // 将显示此悬念边界。
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  );
}

服务器组件与服务器操作

React 19 引入了服务器组件和服务器操作,增强了 React 应用程序的功能。这些功能允许开发者通过将某些任务转移到服务器来优化性能和资源利用率。

React 19 中的改进

ref 作为一个属性

从 React 19 开始,你现在可以在函数组件中将 ref 作为 prop 进行访问,新的函数组件将不再需要 forwardRef

js 复制代码
function MyInput({placeholder, ref}) {
  return <input placeholder={placeholder} ref={ref} />
}

//...
<MyInput ref={ref} />

<Context> 作为提供者

在 React 19 中,你可以直接使用 <Context> 代替 <Context.Provider>

js 复制代码
const ThemeContext = createContext('');

function App({children}) {
  return (
    <ThemeContext value="dark">
      {children}
    </ThemeContext>
  );  
}

refs 支持清理函数

这将使得在 ref 改变时执行清理操作变得更加容易。例如,你可以在 ref 改变时取消订阅事件:

js 复制代码
<input
  ref={(ref) => {
    // ref 创建

    // 新特性: 当元素从 DOM 中被移除时
    // 返回一个清理函数来重置 ref
    return () => {
      // ref cleanup
    };
  }}
/>

当组件卸载时,React 将调用从 ref 回调返回的清理函数。

useDeferredValue 初始化 value

React 19 为 useDeferredValue 新增了 initialValue 参数:

javascript 复制代码
function Search({ deferredValue }) {
  // 首次渲染时值为 ''
  // 随后会调度用 deferredValue 重新渲染
  const value = useDeferredValue(deferredValue, "");
  
  return <Results query={value} />;
}

当提供了 initialValue, useDeferredValue 将在组件的初始渲染中返回它作为 value , 并在后台安排一个使用返回的 deferredValue 重新渲染。

支持文档元数据

文档元数据支持 React 19 原生支持在组件内直接渲染文档元数据标签(<title><link><meta>),无需依赖 react-helmet 等第三方库即可更轻松地管理元数据,确保在客户端渲染、服务端渲染及流式渲染等场景下的兼容性。服务端渲染时需在组件树渲染完成前确保元数据可访问。

js 复制代码
function BlogPost({ post }) {
  return (
    <article>
      <h1>{post.title}</h1>
      <title>{post.title}</title>
      <meta name="author" content="Josh" />
      <link rel="author" href="https://twitter.com/joshcstory/" />
      <meta name="keywords" content={post.keywords} />
      <p>Eee equals em-see-squared...</p>
    </article>
  );
}

支持样式表

内置支持外部样式表和内联样式表管理,允许组件指定样式表优先级。React 将根据优先级自动优化样式表在 DOM 中的插入顺序,简化了并发渲染和服务器的流式渲染中的样式处理。

支持异步脚本

支持在组件树任意位置渲染异步脚本,React 会对多个组件渲染的相同脚本进行去重处理,确保异步脚本只加载一次。

js 复制代码
function MyComponent() {
  return (
    <div>
      <script async={true} src="..." />
      Hello World
    </div>
  );
}

支持预加载资源

在初始文档加载和客户端更新时,尽早告诉浏览器它可能需要加载的资源,可以显著提高页面性能。

React 19 包含了一些新的 API,用于加载和预加载浏览器资源,使得构建不受资源加载效率影响的优秀体验变得尽可能容易。

js 复制代码
import { prefetchDNS, preconnect, preload, preinit } from "react-dom";
function MyComponent() {
  preinit("https://.../path/to/some/script.js", { as: "script" }); // 立即加载并执行此脚本
  preload("https://.../path/to/font.woff", { as: "font" }); // 预加载此字体
  preload("https://.../path/to/stylesheet.css", { as: "style" }); // 预加载此样式表
  prefetchDNS("https://..."); // 当你实际上没有向该主机请求任何东西时
  preconnect("https://..."); // 当你想请求某件事但又不确定是什么的时候
}

兼容第三方脚本和扩展

React 19 改进了激活机制,以考虑第三方脚本和浏览器扩展。

在激活过程中,如果在客户端渲染的元素与从服务器获取的 HTML 中找到的元素不匹配,React 将强制进行客户端重新渲染以修复内容。以前,如果一个元素是由第三方脚本或浏览器扩展插入的,它会触发一个不匹配的错误并进行客户端渲染。

在 React 19 中,<head><body> 中的意外标签将被跳过,避免了不匹配的错误。如果 React 需要由于无关的激活不匹配而重新渲染整个文档,它将保留由第三方脚本和浏览器扩展插入的样式表。

总结

React 19 引入了强大的新功能,例如简化的状态管理、改进的错误处理和简化的异步操作。借助服务器组件和服务器操作,它优化了性能和资源利用率。增强了与第三方脚本和扩展的兼容性,使 React 变得更加好用。

相关推荐
爷_3 小时前
字节跳动震撼开源Coze平台!手把手教你本地搭建AI智能体开发环境
前端·人工智能·后端
charlee444 小时前
行业思考:不是前端不行,是只会前端不行
前端·ai
Amodoro5 小时前
nuxt更改页面渲染的html,去除自定义属性、
前端·html·nuxt3·nuxt2·nuxtjs
Wcowin5 小时前
Mkdocs相关插件推荐(原创+合作)
前端·mkdocs
伍哥的传说6 小时前
CSS+JavaScript 禁用浏览器复制功能的几种方法
前端·javascript·css·vue.js·vue·css3·禁用浏览器复制
lichenyang4536 小时前
Axios封装以及添加拦截器
前端·javascript·react.js·typescript
Trust yourself2436 小时前
想把一个easyui的表格<th>改成下拉怎么做
前端·深度学习·easyui
三口吃掉你6 小时前
Web服务器(Tomcat、项目部署)
服务器·前端·tomcat
Trust yourself2436 小时前
在easyui中如何设置自带的弹窗,有输入框
前端·javascript·easyui
烛阴6 小时前
Tile Pattern
前端·webgl