React 19 新特性详解

React 19 引入了一系列新的功能和改进,旨在简化开发者的工作并提升应用性能。这些改进包括全新的编译器、无需手动优化的 Memoization、简化 Ref 处理的新方法,以及一个新推出的多功能 use() Hook。

React Compiler: 幕后魔法

React 19 的明星功能是它的新编译器。这个编译器将你的 React 代码转换成纯 JavaScript,提升性能,并且免去手动优化的麻烦。

这是图片

示例代码:

// 不再需要 useCallback 或 useMemo
function Component() {
  return <div>优化啦!</div>;
}

解释:新的编译器将 React 代码转化为优化过的 JavaScript,不再需要手动优化(比如使用 memoization)。

告别 Memoization Hooks

使用 useCallbackuseMemomemo 进行手动优化的日子已经结束。新的编译器会在后台优化你的代码,因此你可以专注于编写清晰优雅的 React 组件。

旧版本代码:

// React 18
import React, { useState, useMemo } from "react";

const ExpensiveComponent = () => {
  const [count, setCount] = useState(0);
  const [input, setInput] = useState("");

  // 对开销大的计算进行 memoize
  const expensiveCalculation = useMemo(() => {
    console.log("Calculating...");
    let sum = 0;
    for (let i = 0; i < 1000000000; i++) {
      sum += i;
    }
    return sum;
  }, [count]);

  return (
    <div>
      <h1>Expensive Calculation: {expensiveCalculation}</h1>
      <button onClick={() => setCount(count + 1)}>
        Increment Count ({count})
      </button>
      <input
        type="text"
        value={input}
        onChange={(e) => setInput(e.target.value)}
        placeholder="Type something"
      />
    </div>
  );
};

export default ExpensiveComponent;

新版本代码:

// 无需手动 memoization React 19
function Component({ children }) {
  return <div>{children}</div>;
}

解释:你不再需要使用 useCallbackuseMemo,React 19 会自动处理优化。

无需 forwardRef: 简化 Ref 处理

过去使用 forwardRef 传递 refs 有点麻烦,但在 React 19 中,你可以像传递其他 props 一样传递 refs。

示例代码:

function Child({ innerRef }) {
  return <input ref={innerRef} />;
}

解释:不再需要 forwardRef,refs 现在像普通的 props 一样传递。

新的 use() Hook: 改变游戏规则

新的 use() Hook 取代了多种 hooks,比如用于数据获取的 useEffect 以及用于消耗 Context 数据的 useContextuseState。它通过处理 promises 和 context 使你的代码更为简洁优雅。

旧版本代码:

import React, { useState, useEffect } from "react";

const DataFetchingComponent = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch("https://api.example.com/data");
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) return <p>加载中...</p>;
  if (error) return <p>错误: {error}</p>;

  return (
    <div>
      <h1>数据:</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
};

export default DataFetchingComponent;

新版本代码:

import React, { use } from "react";

// 用于获取数据的函数
async function fetchData() {
  const response = await fetch("https://api.example.com/data");
  if (!response.ok) {
    throw new Error("获取数据失败");
  }
  return response.json();
}

const DataFetchingComponent = () => {
  // `use()` 会在 promise 解析之前挂起组件
  const data = use(fetchData());

  return (
    <div>
      <h1>数据:</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
};

export default DataFetchingComponent;

解释:使用 use() 时,它会在 promise 解析前挂起组件。如果发生错误,它同样可以触发 Suspense 错误边界。你不再需要手动管理数据获取的副作用,React 会在后台处理这些。

Directives: 新的实现方式

如果你使用过 Next.js,可能已经见过 directives。React 19 引入了 directives 来简化组件配置。使用 use client 标记客户端组件,使用 use server 标记服务器端组件。只需在文件顶部添加一行字符串即可。

示例代码:

"use client";
function ClientComponent() {
  return <div>客户端渲染</div>;
}

解释:使用 use clientuse server 来声明客户端或服务器端组件。

Actions: 精简表单处理

表单处理获得了重大升级。Actions 是连接到表单提交的函数,可以在服务器或客户端运行。这意味着代码更加简洁,表单处理过程更加流畅。

示例代码:

async function action(formData) {
  return await handleSubmit(formData);
}

解释:Actions 处理表单提交,可以在客户端或服务器上运行。

useFormStatus() : 管理表单状态

使用 useFormStatus() Hook 来跟踪表单提交状态,例如在表单提交时禁用提交按钮。这对于提供流畅的用户体验非常重要。

示例代码:

const { pending } = useFormStatus();
return <button disabled={pending}>提交</button>;

解释: useFormStatus() 跟踪表单提交状态,比如在提交时禁用按钮。

useFormState() : 有状态的表单操作

useFormState() 是一个用于管理表单状态的新 hook。它类似于 useState ,但它与表单操作一起使用,允许你访问之前的状态和提交的数据。

示例代码:

import React from "react";
import { useForm, useFormState } from "react-hook-form";

const MyForm = () => {
  const { register, handleSubmit, control } = useForm();
  const { isSubmitting, isDirty, isValid } = useFormState({ control });

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label htmlFor="firstName">First Name:</label>
        <input {...register("firstName", { required: true })} />
      </div>
      <div>
        <label htmlFor="lastName">Last Name:</label>
        <input {...register("lastName", { required: true })} />
      </div>
      <button type="submit" disabled={isSubmitting || !isValid}>
        提交
      </button>
      <div>
        <p>表单状态: {isDirty ? "已修改" : "未修改"}</p>
        <p>提交中: {isSubmitting ? "是" : "否"}</p>
      </div>
    </form>
  );
};

export default MyForm;

解释:useFormState 仅在它监视的特定字段更改时重新渲染,使其高效。你可以轻松管理和观察表单状态,而无需编写处理更改和验证的样板代码。

useOptimistic() : 提升用户体验

对于实时应用,useOptimistic() Hook 非常有用。它允许乐观更新,使你的应用感觉更流畅,通过立即更新 UI 并在后台与服务器同步来提升用户体验。

示例代码:

const [optimisticState, setOptimistic] = useOptimistic(initialState);

解释:在与服务器同步之前启用乐观 UI 更新。