React use() Hook 使用指南
概述
use()
是 React 19 引入的新 Hook,它允许你在组件内部直接使用 Promise、Context 和其他可订阅的值。它是一个更通用的数据获取和订阅机制。
基本语法
const value = use(resource);
主要用途
1. Promise 处理
function UserDetails({ userId }: { userId: string }) {const user = use(fetchUser(userId));// 如果 Promise 还未解决,组件会被挂起// 一旦 Promise resolved,组件会重新渲染return (<div><h2>{user.name}</h2><p>{user.email}</p></div>);
}
2. Context 使用
function Button() {const theme = use(ThemeContext);// 等同于 useContext(ThemeContext)return (<button className={theme.buttonClass}>Click me</button>);
}
3. 条件性使用
function DataView({ shouldFetch }: { shouldFetch: boolean }) {if (shouldFetch) {// use() 可以在条件语句中使用const data = use(fetchData());return <div>{data.content}</div>;}return <div>Not fetching</div>;
}
高级用法
1. 并行数据获取
function UserProfile({ userId }: { userId: string }) {const [user, posts, friends] = use(Promise.all([fetchUser(userId),fetchUserPosts(userId),fetchUserFriends(userId)]));return (<div><UserInfo user={user} /><PostList posts={posts} /><FriendList friends={friends} /></div>);
}
2. 嵌套组件中使用
function Comments({ postId }: { postId: string }) {return (<Suspense fallback={<Spinner />}><AsyncComments postId={postId} /></Suspense>);
}function AsyncComments({ postId }: { postId: string }) {const comments = use(fetchComments(postId));return (<ul>{comments.map(comment => (<CommentItem key={comment.id} comment={comment} />))}</ul>);
}
3. 自定义资源
function createResource<T>(promise: Promise<T>) {let status = 'pending';let result: T;let error: Error;const suspender = promise.then((data) => {status = 'success';result = data;},(err) => {status = 'error';error = err;});return {read() {switch (status) {case 'pending':throw suspender;case 'error':throw error;case 'success':return result;}}};
}function DataComponent() {const resource = useMemo(() => createResource(fetchData()), []);const data = use(resource);return <div>{data}</div>;
}
最佳实践
1. 错误边界处理
function ErrorBoundary({ children }: { children: React.ReactNode }) {return (<Suspense fallback={<Spinner />}><ErrorBoundaryInner>{children}</ErrorBoundaryInner></Suspense>);
}function DataComponent() {return (<ErrorBoundary><AsyncContent /></ErrorBoundary>);
}
2. 缓存和预加载
const cache = new Map();function fetchWithCache(key: string) {if (!cache.has(key)) {cache.set(key, fetchData(key));}return cache.get(key);
}function PreloadedData({ id }: { id: string }) {// 预加载数据const data = use(fetchWithCache(id));return <div>{data}</div>;
}
注意事项
-
使用限制:
- 只能在组件内部使用
- 需要配合 Suspense 使用
- 不能在事件处理器中使用
-
性能考虑:
- 合理使用缓存机制
- 避免重复创建资源
- 考虑数据预加载
-
错误处理:
- 使用错误边界捕获异常
- 提供合适的加载状态
- 实现优雅的降级处理
总结
-
use() 的优势:
- 简化异步数据获取
- 支持条件性使用
- 更好的类型推断
- 统一的资源使用方式
-
适用场景:
- 数据获取
- Context 消费
- 自定义订阅
- 并行数据加载
-
使用建议:
- 配合 Suspense 使用
- 实现适当的错误处理
- 注意性能优化
- 合理组织代码结构