获取异步数据
在 React 18 及以前版本中,异步获取数据的操作一般都是通过 Axios 或者 fetch 功能来完成的。但是在 Canary 和 Experimental 发布渠道中,React 新提供了一个use
函数来从 Promise 和 Context 中获取内容。
使用 fetch 搭配自定义 Hook 完成异步
fetch 和 Axios 都是用来完成对服务端进行数据异步访问的,它们之间仅有一些使用上的不同。由于 React 里很多 Hook 都要求同步操作,尤其是useEffect
中,所以在使用 fetch 或者 Axios 访问服务端数据时,一般都需要自定义一个 Hook 来简化组件中对于异步数据的访问。
以下是一个基于 fetch 使用 GET 方式访问 RESTful API 服务的自定义 Hook 示例。
import { useEffect, useState } from "react";
export function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url);
if (!response.ok) {
throw new Error("Network response was not ok");
}
const result = await response.json();
setData(result);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
在这个示例中,需要注意的是,useEffect
Hook 中只能使用同步函数,所以即便是使用async/await
定义了异步函数,也需要使用其同步调用方式。
使用use
获取异步数据 🧪
本章节的内容在当前React 18版本中是不可用的,如果需要尝试本章节介绍的内容需要使用Canary或者Experimental发布渠道。预计在未来React 19版本中,本章的内容将被发布至正式版。
use
不是一个 Hook,而是一个普通的函数,所以她可以在循环语句和条件判断语句中调用,但是调用use
的函数依旧需要是一个组件或者 Hook。
使用use
读取 Context 中的内容时十分简单,基本上与useContext
一样。参见以下示例。
import { use } from "react";
function ThemedPage() {
const theme = use(ThemeContext);
// ...
}
但是当use
与 Promise 结合使用的时候,效果就不一样了。use
可以在调用异步过程的时候暂停组建的渲染过程,这也就是说use
可以与<Suspense>
组件一起搭配使用。当调用use
的组件被<Suspense>
包裹的时候,组件被use
挂起时,将展示fallback
指定的内容,直到use
参数中的 Promise 被解决。如果use
中的 Promise 出现错误,那么最近的错误边界中的后备 UI 将被展示。
以下示例展示的是利用 Promise 从服务端获取数据的用法。
import { Suspense, use } from "react";
function Message({ messagePromise }) {
const messageContent = use(messagePromise);
return <div>Message: {messageContent}</div>;
}
function App() {
const messagePromise = async () => {
const response = await fetch("/message");
return response.text();
};
return (
<Suspense fallback={<div>Loading...</div>}>
<Message messagePromise={messagePromise} />
</Suspense>
);
}
现在对比一下上面传统使用自定义 Hook 实现的异步操作,是不是已经简单了很多。
在有async/await
加持的条件下,Promise 被 reject 时,往往可以使用try/catch
来处理,但是在使用use
捕获 Promise 返回的值时,是不可以使用try/catch
的。作为替代方案,需要使用错误便边界。
错误边界的定义不在 React 中提供,函数式组件中目前也没有提供处理错误的错误边界功能。所以错误边界功能目前还是由传统的使用类编写组件的方式实现的,一般情况下,可以使用react-error-boundary
库来支持错误边界,其中提供的<ErrorBoundary>
组件的使用与 React 中提供的<Suspense>
组件的使用基本上是一致的。