在 React 19 中使用新的 use() Hook,实现更简洁的 Async Components

发布: (2026年3月9日 GMT+8 02:07)
6 分钟阅读
原文: Dev.to

Source: Dev.to

Teguh Coding

如果你已经使用 React 一段时间了,可能已经体会到在组件中处理异步数据的头疼。useEffectuseState 以及各种数据获取库的组合,往往会让代码变得杂乱。React 19 引入了一个改变游戏规则的解决方案:use() Hook。

让我来展示一下这个新 Hook 如何简化异步数据处理,让你的代码变得更加清晰。

旧方式:冗长且易出错

在 React 19 之前,在组件内部获取数据的写法大致如下:

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    setLoading(true);
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err);
        setLoading(false);
      });
  }, [userId]);

  if (loading) return ;
  if (error) return ;

  return {user.name};
}

这段代码为了一个简单的数据获取就写了大量模板代码。你必须管理三种不同的状态,正确处理 effect 的依赖,并且希望没有遗漏任何边缘情况。

新方式:简洁且声明式

React 19 的 use() Hook 改变了一切。它在 promise 解析期间挂起组件,在组件树的更高层处理加载和错误状态。

import { use } from 'react';

function UserProfile({ userId }) {
  const user = use(fetchUser(userId));

  return {user.name};
}

就是这样。无需状态管理、无需副作用、无需样板代码。组件只会等待 promise 解析。

实际工作原理

use() Hook 接受一个 Promise,并且:

  • 挂起 组件(如果 Promise 仍在 pending 状态)
  • 恢复 并使用已解析的值(当 Promise 完成时)
  • 抛出 错误(如果 Promise 被拒绝),你可以在错误边界中捕获它

下面是一个完整示例,展示真实的数据获取场景:

import { use, Suspense, ErrorBoundary } from 'react';

// Async function that returns a promise
async function fetchUser(userId) {
  const res = await fetch(`/api/users/${userId}`);
  if (!res.ok) throw new Error('Failed to fetch user');
  return res.json();
}

function UserProfile({ userId }) {
  const user = use(fetchUser(userId));

  return (
    <>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
      <span>{user.role}</span>
    </>
  );
}

// Wrap it with Suspense and ErrorBoundary
function App() {
  return (
    <ErrorBoundary fallback={<div>Something went wrong.</div>}>
      <Suspense fallback={<div>Loading...</div>}>
        <UserProfile userId="123" />
      </Suspense>
    </ErrorBoundary>
  );
}

处理多个异步值

其中一个最佳特性是 use() 优雅地处理多个 Promise:

function Dashboard({ userId }) {
  const [user, posts] = use(Promise.all([
    fetchUser(userId),
    fetchPosts(userId)
  ]));

  return (
    <>
      <h2>Welcome, {user.name}</h2>
      {/* render posts here */}
    </>
  );
}

不再需要 Promise.all + useState + useEffect 组合——直接在组件中编写异步代码即可。

与现有模式集成

您仍然可以在已有的数据获取库中使用 use()。例如,配合 TanStack Query

import { useQuery } from '@tanstack/react-query';
import { use } from 'react';

function UserAvatar({ userId }) {
  const query = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUser(userId)
  });

  // 转换为 Promise 供 use() 使用
  const user = use(
    query.isSuccess ? Promise.resolve(query.data) : new Promise(() => {})
  );

  return <img src={user.avatar} alt={user.name} />;
}

或者创建一个简单的包装函数:

function useAsync(asyncFn) {
  return use(Promise.resolve().then(() => asyncFn()));
}

function UserCard({ userId }) {
  const user = useAsync(() => fetchUser(userId));
  return {user.name};
}

正确的错误处理

use() 钩子与 React 的错误边界(Error Boundary)模式完美结合:

function PostWithComments({ postId }) {
  const post = use(fetchPost(postId));
  const comments = use(fetchComments(postId));

  return (
    <>
      <h2>{post.title}</h2>
      <p>{post.content}</p>
      {/* render comments here */}
    </>
  );
}

// 组件树中的任何错误都会冒泡到错误边界
function ErrorFallback({ error }) {
  return <div>出现了一些问题:{error.message}</div>;
}

function App() {
  return (
    <ErrorBoundary fallback={<ErrorFallback />}>
      <Suspense fallback={<div>加载中…</div>}>
        <PostWithComments postId="456" />
      </Suspense>
    </ErrorBoundary>
  );
}

何时使用 use()useEffect

使用 use() 的情况:

  • 需要获取在组件中渲染的数据。
  • 想要更简洁、更易读的异步代码。
  • 正在构建时考虑使用 Suspense。

坚持使用 useEffect 的情况:

  • 处理副作用(日志、分析、订阅)。
  • 数据直接影响渲染输出。

为什么在组件中渲染?

  • 您需要对 何时 获取进行细粒度控制。

更宏观的视角

use() hook 不仅仅是语法糖——它是 React 对 “React 19:异步时代” 的愿景的一部分。
结合 Server Components(服务器组件)和 Actions(动作),它标志着我们构建 React 应用方式的根本转变。

不再需要在每个组件中单独管理加载状态,而是只在顶层定义一次,让 React 负责其余的工作。
这提供了更简洁的思维模型,并且可以减少代码量。

试一试

如果你使用 React 19(或 beta 版),可以开始在组件中尝试 use()。你会惊讶于样板代码消失得多快,以及你的异步代码变得多么易读。

React 的未来是原生异步的。拥抱它吧。

你对新的 use() Hook 有何看法?
你已经尝试过了吗?在下方评论区留下你的想法吧。

0 浏览
Back to Blog

相关文章

阅读更多 »