首页 / React 19 入门教程 / use Hook

React 19 入门教程

use Hook

本教程共 50 篇 · 第 43 篇 · 更新于 2026-07-29 · 约 7 分钟阅读

ReactusePromiseContextSuspenseReact 19

43. use Hook

本节目标:学会 React 19 的 use Hook,用更灵活的方式读取 Promise 和 Context。

use 不是你以为的那个 Hook

React 19 新增了一个叫 use 的 API。它名字以 use 开头,但不是 Hook——可以在条件语句和循环里调用,这是普通 Hook 不允许的。use 是一个特殊的 React API,不受 Hook 调用规则限制。

use 能读取两种东西:PromiseContext

import { use } from 'react';

// 读取 Context
const theme = use(ThemeContext);

// 读取 Promise
const data = use(dataPromise);

use 读取 Context:替代 useContext

以前读 Context 用 useContext,有个限制——只能在组件顶层调用:

// useContext 不能放在条件里
function Button() {
  if (someCondition) {
    const theme = use(ThemeContext);  // ❌ 报错
  }
}

use 没有这个限制:

import { use } from 'react';

function Button({ show }) {
  if (show) {
    const theme = use(ThemeContext);  // ✅ 可以
    return <button className={theme}>按钮</button>;
  }
  return null;
}

行为上和 useContext 一样——找最近的 Provider,拿它的 value。

Note

use(Context)useContext(Context) 效果完全一样。use 只是多了一个”可以条件调用”的灵活性。

use 读取 Promise:新数据获取方式

use(Promise) 是 React 19 最强大的新功能之一。它让组件可以直接”等待”Promise 完成:

import { use, Suspense } from 'react';

function Message({ messagePromise }) {
  const content = use(messagePromise);
  return <p>{content}</p>;
}

function App() {
  const messagePromise = fetch('/api/message').then(r => r.text());

  return (
    <Suspense fallback={<p>加载中……</p>}>
      <Message messagePromise={messagePromise} />
    </Suspense>
  );
}

use(messagePromise) 做了什么?

  1. 如果 Promise 还没完成 → 组件”挂起”(suspend),显示 Suspense fallback
  2. 如果 Promise 已完成 → 直接返回 resolved 的值
  3. 如果 Promise 被拒绝 → 抛出错误,由错误边界捕获

Promise 必须缓存

这是最容易踩的坑。use 接收的 Promise 必须是同一个实例,否则会无限循环:

// ❌ 错误:每次渲染创建新 Promise
function Message() {
  const data = use(fetch('/api/message'));  // 每次都发新请求
  return <p>{data}</p>;
}
// ✅ 正确:Promise 在组件外部创建并缓存
let cache = new Map();

function fetchData(url) {
  if (!cache.has(url)) {
    cache.set(url, fetch(url).then(r => r.json()));
  }
  return cache.get(url);
}

function Message() {
  const data = use(fetchData('/api/message'));  // 同一个 Promise
  return <p>{data}</p>;
}

或者用 Suspense 兼容的数据源(框架内置的 fetch、TanStack Query 的 suspense 模式),它们自带缓存。

Warning

在组件内部直接 use(fetch(url)) 会导致:挂起 → 显示 fallback → 重新渲染 → 创建新 Promise → 又挂起 → 无限循环。

条件调用:use 的杀手锏

普通 Hook 不能条件调用,use 可以。这在某些场景下非常有用:

function UserProfile({ showDetails }) {
  let name = '加载中';
  let email = '';

  if (showDetails) {
    // 条件调用 use —— 普通 Hook 做不到
    const user = use(userPromise);
    name = user.name;
    email = user.email;
  }

  return (
    <div>
      <h2>{name}</h2>
      {email && <p>{email}</p>}
    </div>
  );
}

showDetails 为 false 时,不读 Promise,不挂起。为 true 时才开始读。

配合 Suspense 和错误边界

use(Promise) 需要两个”保护伞”:

import { use, Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';

function App() {
  return (
    <ErrorBoundary fallback={<p>加载失败</p>}>
      <Suspense fallback={<p>加载中……</p>}>
        <Message messagePromise={fetchMessage()} />
      </Suspense>
    </ErrorBoundary>
  );
}
  • Suspense:处理”加载中”状态
  • ErrorBoundary:处理”加载失败”状态

少了任何一个,用户体验都不完整。

服务端组件传 Promise 到客户端

React Server Components 可以创建 Promise,传给客户端组件:

// 服务端组件
import { fetchMessage } from './api.js';
import { Message } from './Message.js';

export default function App() {
  const messagePromise = fetchMessage();  // 服务端开始请求
  return (
    <Suspense fallback={<p>加载中……</p>}>
      <Message messagePromise={messagePromise} />
    </Suspense>
  );
}
// 客户端组件
'use client';
import { use } from 'react';

export function Message({ messagePromise }) {
  const content = use(messagePromise);  // 客户端读取同一个 Promise
  return <p>{content}</p>;
}

请求在服务端就开始,客户端只需要”等待”结果。这就是 React 19 的数据流式传输。

use vs useEffect 获取数据

useEffect + useStateuse + Suspense
代码量多(3 个 state)少(1 行)
竞态条件手动处理自动处理
瀑布问题容易出现容易避免
错误处理手动 try/catch错误边界
缓存手动实现需要缓存 Promise
心智模型命令式声明式

use 不是要替代 useEffect,而是提供了一种更声明式的选择。对于”等数据到了再渲染”的场景,use 更简洁。

Tip

如果你已经在用 TanStack Query 或 SWR,它们的 Suspense 模式底层就是类似 use 的机制。直接用库就行,不用自己管理 Promise 缓存。