use Hook
本教程共 50 篇 · 第 43 篇 · 更新于 2026-07-29 · 约 7 分钟阅读
43. use Hook
本节目标:学会 React 19 的
useHook,用更灵活的方式读取 Promise 和 Context。
use 不是你以为的那个 Hook
React 19 新增了一个叫 use 的 API。它名字以 use 开头,但不是 Hook——可以在条件语句和循环里调用,这是普通 Hook 不允许的。use 是一个特殊的 React API,不受 Hook 调用规则限制。
use 能读取两种东西:Promise 和 Context。
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) 做了什么?
- 如果 Promise 还没完成 → 组件”挂起”(suspend),显示 Suspense fallback
- 如果 Promise 已完成 → 直接返回 resolved 的值
- 如果 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 + useState | use + Suspense | |
|---|---|---|
| 代码量 | 多(3 个 state) | 少(1 行) |
| 竞态条件 | 手动处理 | 自动处理 |
| 瀑布问题 | 容易出现 | 容易避免 |
| 错误处理 | 手动 try/catch | 错误边界 |
| 缓存 | 手动实现 | 需要缓存 Promise |
| 心智模型 | 命令式 | 声明式 |
use 不是要替代 useEffect,而是提供了一种更声明式的选择。对于”等数据到了再渲染”的场景,use 更简洁。
Tip如果你已经在用 TanStack Query 或 SWR,它们的 Suspense 模式底层就是类似
use的机制。直接用库就行,不用自己管理 Promise 缓存。