react19新API之use()用法总结

React use() Hook 使用指南

概述

use() 是 React 19 引入的新 Hook,它允许你在组件内部直接使用 Promise、Context 和其他可订阅的值。它是一个更通用的数据获取和订阅机制。

基本语法

typescript 复制代码
const value = use(resource);

主要用途

1. Promise 处理

typescript 复制代码
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 使用

typescript 复制代码
function Button() {
  const theme = use(ThemeContext);
  // 等同于 useContext(ThemeContext)
  
  return (
    <button className={theme.buttonClass}>
      Click me
    </button>
  );
}

3. 条件性使用

typescript 复制代码
function DataView({ shouldFetch }: { shouldFetch: boolean }) {
  if (shouldFetch) {
    // use() 可以在条件语句中使用
    const data = use(fetchData());
    return <div>{data.content}</div>;
  }
  return <div>Not fetching</div>;
}

高级用法

1. 并行数据获取

typescript 复制代码
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. 嵌套组件中使用

typescript 复制代码
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. 自定义资源

typescript 复制代码
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. 错误边界处理

typescript 复制代码
function ErrorBoundary({ children }: { children: React.ReactNode }) {
  return (
    <Suspense fallback={<Spinner />}>
      <ErrorBoundaryInner>
        {children}
      </ErrorBoundaryInner>
    </Suspense>
  );
}

function DataComponent() {
  return (
    <ErrorBoundary>
      <AsyncContent />
    </ErrorBoundary>
  );
}

2. 缓存和预加载

typescript 复制代码
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>;
}

注意事项

  1. 使用限制:

    • 只能在组件内部使用
    • 需要配合 Suspense 使用
    • 不能在事件处理器中使用
  2. 性能考虑:

    • 合理使用缓存机制
    • 避免重复创建资源
    • 考虑数据预加载
  3. 错误处理:

    • 使用错误边界捕获异常
    • 提供合适的加载状态
    • 实现优雅的降级处理

总结

  1. use() 的优势:

    • 简化异步数据获取
    • 支持条件性使用
    • 更好的类型推断
    • 统一的资源使用方式
  2. 适用场景:

    • 数据获取
    • Context 消费
    • 自定义订阅
    • 并行数据加载
  3. 使用建议:

    • 配合 Suspense 使用
    • 实现适当的错误处理
    • 注意性能优化
    • 合理组织代码结构
相关推荐
humors2217 小时前
Deepseek工具:H5+Vue 项目转微信小程序报告生成工具
前端·vue.js·微信小程序·h5·工具·报告
方安乐7 小时前
ESLint代码规范(二)
前端·javascript·代码规范
zzginfo7 小时前
var、let、const、无申明 四种变量在赋值前,使用的情况
开发语言·前端·javascript
贺小涛7 小时前
Vue介绍
前端·javascript·vue.js
cch89188 小时前
React Hooks的支持
前端·javascript·react.js
ofoxcoding8 小时前
React 性能优化实战:我把一个卡成 PPT 的页面优化到丝滑的全过程
javascript·react.js·ai·性能优化
鹏程十八少8 小时前
9. Android Shadow插件化如何解决资源冲突问题和实现tinker热修复资源(源码分析4)
android·前端·面试
蜡台8 小时前
vue.config.js 配置
前端·javascript·vue.js·webpack
qq_381338508 小时前
微前端架构下的状态管理与通信机制深度解析:从 qiankun 源码到性能优化实战
前端·状态模式