

多年来,React 开发者习惯使用 useContext 在全局共享状态,而不用把 props 一层层传递下去。虽然这种方式可行,但即将到来的 use() API 带来了更强大的能力,远远超越了单纯读取 context 的功能。

通过 use(),你不仅能做到 useContext 可以做到的一切,还能直接在组件中无缝处理异步数据,比如 API 调用或 Promise。这意味着更统一的写法、更干净的代码,以及一种全新的状态管理和数据获取思路。
在本文结束时,你将清楚理解 use() API 如何改善现代 React 中的状态管理和数据获取方式。
在继续之前,你需要准备:
我们用 Vite 来初始化一个 React 项目。 打开终端并运行:
npm create vite@latest my-project接着进入项目目录:
cd my-project然后启动开发服务器:
npm run dev本文示例会使用 Tailwind CSS 来做样式。
在 React 的新 use() API 出现之前,若要从 API 获取数据,你需要导入并使用三个 Hook,例如:
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);这种写法显得冗长:你需要同时管理三个状态变量(data、loading、error),并结合 useEffect 来触发请求,例如:
import React, { useState, useEffect } from 'react';
function DataFetcher() {
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');
if (!response.ok) {
throw new Error('Failed to fetch data');
}
const result = await response.json();
setData(result);
} catch (e) {
setError(e);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) {
return <div>加载中...</div>;
}
if (error) {
return <div>错误: {error.message}</div>;
}
return (
<div>
{/* 在此渲染数据 */}
</div>
);
}这个组件通过 useEffect 拉取 API 数据,并用 useState 管理状态。它初始化了三个状态:data 存放结果,loading 表示加载状态,error 捕获请求错误。当组件挂载时,会触发异步函数请求数据,成功则存入 data,失败则存入 error。
接下来看 use() 的场景。使用 use,你不再需要手动管理这三个状态,也不需要 useEffect 来触发请求。
use() 可以直接在组件中读取 Promise 的值,无需 useEffect 与 useState 来单独管理 loading 和 error。与普通 Hook 不同,它可以在循环和条件语句中运行,但依然必须在组件或 Hook 内部调用。
结合 Suspense,它可以以最小的配置实现丝滑的加载体验。语法如下:
const value = use(resource);我们来实际体验一下 use 的威力。
设置 API 调用 在 src 文件夹中创建 api.js,粘贴如下代码:
let usersPromise;
async function fetchUsers() {
const response = await fetch('<https://jsonplaceholder.typicode.com/users>');
if (!response.ok) {
throw new Error('Failed to fetch users');
}
return response.json();
}
export function getUsersPromise() {
if (!usersPromise) {
usersPromise = fetchUsers();
}
return usersPromise;
}上面的 API 调用中,我们通过 getUsersPromise 来缓存(memoize)Promise,这样即便组件重新渲染,数据也只会请求一次。接着我们用 use 来解包这个 Promise。
创建 UserList.jsx 并添加如下导入:
import React, { use } from 'react';
import { getUsersPromise } from './api';然后写组件:
function UserList() {
const users = use(getUsersPromise());
return (
<div>
<h1 className='text-center py-5 text-2xl font-bold'>用户列表</h1>
<ul className='grid grid-cols-5 gap-5'>
{users.map((user) => (
<li key={user.id} className=' bg-gray-500 py-10 text-center rounded-[5px] text-gray-200'>
<strong>{user.name}</strong> - {user.email}
</li>
))}
</ul>
</div>
);
}
export default UserList;这里我们把 getUsersPromise 传给了 use,这样它会直接解包返回的 Promise,并赋值给 users。接着我们遍历并渲染数据。
你注意到没有?这里完全不需要 useState 和 useEffect! 得益于 use,我们可以声明式地处理数据请求、渲染,以及加载与错误处理。接下来我们还会结合 Suspense 和 ErrorBoundary 来进一步优化用户体验。
use API 借助 Suspense 和 ErrorBoundary 来管理不同状态。由于 React 没有内置 ErrorBoundary,我们需要自己实现。 在项目中新建 ErrorBoundary.jsx 并粘贴以下代码:
import React from "react";
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error: error };
}
componentDidCatch(error, errorInfo) {
console.error("未捕获错误:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div className="p-10 text-center text-red-700 font-bold border-2 border-solid border-red-800">
<h2>出错了。</h2>
<p>{this.state.error && this.state.error.message}</p>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;该组件能捕获子组件树中任意错误,使用了两个生命周期方法:
static getDerivedStateFromError(error)componentDidCatch(error, errorInfo)第一个在抛出错误后触发,第二个在状态更新后触发。
修改 App.jsx 内容如下:
import React, { Suspense } from "react";
import UserList from "./UserList";
import ErrorBoundary from "./ErrorBoundary";
const FallbackLoader = () => (
<div className="p-10 text-center font-bold">正在加载用户...</div>
);
function App() {
return (
<div className="App bg bg-gray-200 h-screen w-screen flex flex-col items-center justify-center px-5">
<main>
<ErrorBoundary>
<Suspense fallback={<FallbackLoader />}>
<UserList />
</Suspense>
</ErrorBoundary>
</main>
</div>
);
}
export default App;FallbackLoader 组件提供加载时的占位 UI。 在 App 中,我们用 Suspense 包裹 <UserList/>,并传入 FallbackLoader 作为 fallback,再外层加上 ErrorBoundary 处理错误。
运行 npm run dev 即可看到效果。

接下来,我们给应用加上 暗黑模式。
为了展示 use API 如何超越 useContext,我们来实现暗黑模式。 在 use 出现之前,如果要实现暗黑模式,你大概率会用 useContext,例如:
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => setTheme(theme === 'light' ? 'dark' : 'light');
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};然后通过 useContext 访问:
const ThemeToggle = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<button onClick={toggleTheme}>
切换到 {theme === 'light' ? '深色' : '浅色'} 模式
</button>
);
};而使用 use,写法更简洁。
创建 ThemeContext.jsx 并写入:
import React, { createContext, useState, useEffect } from "react";
const ThemeContext = createContext(null);
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState(() => {
const savedTheme = localStorage.getItem("theme");
return savedTheme || "light";
});
useEffect(() => {
document.body.setAttribute("data-theme", theme);
localStorage.setItem("theme", theme);
}, [theme]);
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
export default ThemeContext;然后在 UserList.jsx 中引入:
import ThemeContext from './contexts/ThemeContext';并通过 use 来消费 context:
const { theme } = use(ThemeContext);更新后的 UserList.jsx:
import React, { use } from 'react';
import { getUsersPromise } from './api';
import ThemeContext from './contexts/ThemeContext';
function UserList() {
const { theme } = use(ThemeContext);
const users = use(getUsersPromise());
return (
<div>
<h1 className='text-center py-5 text-2xl font-bold text-gray-900 dark:text-gray-100 transition-colors duration-300'>
用户列表
</h1>
<ul className='grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-5'>
{users.map((user) => (
<li
key={user.id}
className='py-10 text-center rounded-[5px] shadow-md bg-gray-500 text-gray-200 dark:bg-gray-700 dark:text-gray-100 transition-colors duration-300 ease-in-out'
>
<strong>{user.name}</strong> - {user.email}
</li>
))}
</ul>
</div>
);
}
export default UserList;接着在 App.jsx 中引入并实现 ThemeToggle,完整内容这里省略。
运行后,你将看到用户列表支持明暗模式切换。
虽然 use 很强大,但仍有一些限制:
use 的 Promise 必须被缓存,否则会导致无限循环。例如把 getUsersPromise 改成直接返回 fetchUsers():
export function getUsersPromise() {
return fetchUsers();
}运行后你会发现网络请求无限触发。 这是因为每次渲染都会生成新的 Promise,从而再次触发 Suspense,导致组件不断重新挂起。
因此,推荐始终搭配 Suspense + ErrorBoundary 来使用,以保证良好的用户体验。
一句话总结: use() API 是 React 的一次重大飞跃,尤其在服务端优先(server-first)应用中,它能替代很多 useContext 的场景,并带来更强的异步友好能力。
在本教程中,我们体验了 use() 的应用:解包 Promise、结合 Suspense 与错误边界,以及无需样板代码即可实现主题切换。
有了 use(),状态管理和数据获取更简洁、更直观,也让现代 React 应用的开发变得更高效、顺滑。