精读React hook(十六):一个为代码优雅而生的hook——use

use 是 React 官方最新推出的 hook(截止2023.9.21),本文也是《精读React hook》系列文章的最后一篇。

截止发文日期,use 还是一个预发布的 hook,将来有可能会进行破坏性更新,所以不推荐在生产环境使用。但这不妨碍我们学习,万一过段时间 use 转正了呢?

use的使用

use 可以让你在函数组件中读取类似于 Promise 或 context 的资源的值。它的基础用法如下:

jsx 复制代码
import { use } from 'react';

function MessageComponent({ messagePromise }) {
  const message = use(messagePromise);
  const theme = use(ThemeContext);
  // ...
}

use 函数的参数是你想要读取的资源,资源可以是 Promise 或 Context(在这个例子中是 messagePromiseThemeContext),并返回从资源中读取的值。

use解决的问题场景

在过去,React 开发者在处理类似于 Promise 或 Context 的资源时,通常需要将这些资源的值存储在 state 中,然后在组件中通过 props 或 state 来使用这些值。这种方法虽然可行,但是会增加代码的复杂性,并可能导致状态管理的困难。

use 这个 hook 解决了这个问题,因为它让你能够直接在组件中调用并获取这些资源的值,这样可以简化代码,使其更易于理解和维护。

想象一个场景,加入你正在开发一个博客应用,这个应用需要从 API 获取博客文章的内容,不用 use 的时候,你会这么做:

jsx 复制代码
import { useState, useEffect } from 'react';

function BlogPostComponent({ postId }) {
  const [post, setPost] = useState(null);

  useEffect(() => {
    fetchPost(postId).then(data => setPost(data));
  }, [postId]);

  // ...
}

用上 use,就可以这么做:

jsx 复制代码
import { use } from 'react';

function BlogPostComponent({ postId }) {
  const postPromise = fetchPost(postId);
  const post = use(postPromise);
  // ...
}

在功能上是一样的,但是用了 use 明显代码更优雅了。

use用于条件语句和循环中

其他 React hook 不同,use 可以在组件里的循环和条件语句中使用。例如:

  • 根据博客内容类别,读取不同 Promise
jsx 复制代码
import { use } from 'react';

function ResourceComponent({ resourceType }) {
  let resource;

  if (resourceType === 'post') {
    const postPromise = fetchPost();
    resource = use(postPromise);
  } else if (resourceType === 'comment') {
    const commentPromise = fetchComment();
    resource = use(commentPromise);
  }

  // ...
}
  • 在组件里读取一个包含多个资源的数组
jsx 复制代码
import { use } from 'react';

function ResourceListComponent({ resourcePromises }) {
  const resources = resourcePromises.map(resourcePromise => use(resourcePromise));

  // ...
}

将数据从服务器流式传递给客户端

了解 NextJS v13 的同学都知道,在 app router 模式下,你可以在服务端组件里面嵌套客户端组件,而这种方式就能实现把服务端组件获取的数据传递给客户端组件。这是本节要讲述的知识的基础,如果你还不懂这些概念,可以到我的另一篇文章《NextJS v13服务端组件和客户端组件及最佳实践》学习一下。

以下是一个示例,展示了如何在服务器组件中创建一个Promise,并将其作为prop传递给客户端组件:

jsx 复制代码
// 服务器组件
function ServerComponent({ postId }) {
  const postPromise = fetchPost(postId);
  return <ClientComponent postPromise={postPromise} />;
}

// 客户端组件
import { use } from 'react';

function ClientComponent({ postPromise }) {
  const post = use(postPromise);
  // ...
}

ClientComponent 中,我们使用 use 这个Hook来读取 **ServerComponent** 传过来的 Promise。

如果不用 use ,我们也可以在 ServerComponentawait 来完成请求,然后把请求结果通过prop传给 ClientComponent ,不过 await 会在执行完成前阻塞服务端组件的渲染,而使用 use 不会影响服务端组件的渲染。

处理 rejected Promise

有 Promise 的地方就要提供处理 rejected Promise 的方法。当你使用use的时候,有以下两种方法可以处理 rejected Promise:

1、ErrorBoundary

我们可以用 ErrorBoundary 包裹可能出错的组件,如果传递给 **use** 的 Promise rejected 了,将显示 ErrorBoundary 的 fallback:

jsx 复制代码
"use client";
import { use, Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";

export function BlogPostComponent() {
  const postPromise = fetchPost(postId);

  return (
    <ErrorBoundary fallback={<p>⚠️Something went wrong</p>}>
      <Suspense fallback={<p>⌛Loading...</p>}>
        <BlogPostTitle messagePromise={messagePromise} />
      </Suspense>
    </ErrorBoundary>
  );
}

function BlogPostTitle({ postPromise }) {
  const post = use(postPromise);
  // ...

	return <p>Here is the title: {post.title}</p>;
}

2、Promise.catch

如果你不想用 ,但又想在 rejected 时有值填充,可以使用 Promise 的 catch 方法。

jsx 复制代码
"use client";
import { use, Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";

export function BlogPostComponent() {
const postPromise = fetchPost(postId).catch((error) => {
    console.error('Failed to fetch post:', error);
    return 'https://weijunext.com'; // 返回一个默认值
  });

  return (
    <Suspense fallback={<p>⌛Loading...</p>}>
      <BlogPostTitle messagePromise={messagePromise} />
    </Suspense>
  );
}

结语

use 还只是一个实验性,等它正式转正之后,想必也会成为社区里宣传 React 代码优化之道的一项指南。

专栏结语

写完这篇文章,《👉精读React Hooks》专栏就算告一段落了。本系列文章讲解了 16 个官方文档里列出来的 hook,其中前面一半在我们日常开发中经常使用,而后面一半其实鲜有使用,这是因为后来发布的 hook 主要面向库或者上层框架的开发者。React 源码里导出的其实还不止这 16 个 hook,这是因为其它 hook 对绝大部分开发者来说是绝无机会使用到的。

本专栏的编写算是我的一条支线任务,完成本专栏的编写后,我会继续回归主线任务------实战项目的经验分享。我的工作和 side project 会用到的核心技术栈有:Next.js、React、Vue、Node,如果你有兴趣一起探讨相关知识,不妨关注一下👉我的掘金账号

专栏资源

专栏博客地址:👉 精读React Hooks

专栏演示站:👉 React Hooks Demos

专栏源码:👉 Github

专栏文章列表:

精读React hook(一):useState 的几个基础用法和进阶技巧

精读React hook(二):React状态管理的强大工具------useReducer

精读React hook(三):useContext从基础应用到性能优化

精读React hook(四):useRef的多维用途

精读React hook(五):useEffect使用细节知多少?

精读React hook(六):useLayoutEffect解决了什么问题?

精读React hook(七):用useMemo来减少性能开销

精读React hook(八):我们为什么需要useCallback

精读React hook(九):使用useTransition进行非阻塞渲染

精读React hook(十):使用useDeferredValue来做状态延迟更新

精读React hook(十一):useInsertionEffect------CSS-in-JS样式注入新方式

精读React hook(十二):使用useImperativeHandle能获得什么能力

精读React hook(十三):使用useSyncExternalStore获取实时数据

精读React hook(十四):总有一天你会需要useId为你生成唯一id

精读React hook(十五):把useDebugValue加入你的React调试工具库

精读React hook(十六):一个为代码优雅而生的hook------use

相关推荐
挣扎与觉醒中的技术人3 分钟前
【技术干货】三大常见网络攻击类型详解:DDoS/XSS/中间人攻击,原理、危害及防御方案
前端·网络·ddos·xss
zeijiershuai7 分钟前
Vue框架
前端·javascript·vue.js
写完这行代码打球去9 分钟前
没有与此调用匹配的重载
前端·javascript·vue.js
华科云商xiao徐9 分钟前
使用CPR库编写的爬虫程序
前端
狂炫一碗大米饭12 分钟前
Event Loop事件循环机制,那是什么事件?又是怎么循环呢?
前端·javascript·面试
IT、木易13 分钟前
大白话Vue Router 中路由守卫(全局守卫、路由独享守卫、组件内守卫)的种类及应用场景
前端·javascript·vue.js
顾林海14 分钟前
JavaScript 变量与常量全面解析
前端·javascript
程序员小续14 分钟前
React 组件库:跨版本兼容的解决方案!
前端·react.js·面试
乐坏小陈15 分钟前
2025 年你希望用到的现代 JavaScript 模式 【转载】
前端·javascript
生在地上要上天15 分钟前
从600行"状态地狱"到可维护策略模式:一次列表操作限制重构实践
前端