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 使用
    • 实现适当的错误处理
    • 注意性能优化
    • 合理组织代码结构
相关推荐
陈随易1 分钟前
VSCode v1.99发布,王者归来,Agent和MCP正式推出
前端·后端·程序员
青青奇犽4 分钟前
Vue 组件通信全解析:七种核心方式与最佳实践
前端·vue.js·面试
忆柒5 分钟前
理解 JavaScript 原型和继承:从原型链到类的演变
javascript·面试
你的人类朋友5 分钟前
CommonJS模块化规范
javascript·后端·node.js
青青奇犽6 分钟前
页面渲染优化:提升性能的关键策略🚀
前端·vue.js·面试
小爱同学_6 分钟前
从经典面试题事件委托到撩妹
前端·javascript·面试
FanetheDivine6 分钟前
solid: react导演剪辑终极扑街版
前端·react.js
卖报的小行家_8 分钟前
Vue2源码,响应式原理-对象
前端
小钰能吃三碗饭9 分钟前
打造类 RainbowKit 的 Solana 钱包连接套件
前端·web3·区块链
Anlici12 分钟前
如何优化十万数据的浏览体验?从性能、监控到布局全面拆解
前端·性能优化