您可能习惯于在 React 中使用 axios 或 fetch 获取数据。处理数据获取的常用方法是
- 进行 API 调用。
- 如果一切按计划进行,则使用响应更新状态。
- 或者,在遇到错误的情况下,向用户显示错误消息。
在处理网络上的请求时,总会存在延迟。这是进行请求并等待响应时必须面对的一部分。这就是为什么我们经常使用加载指示器来向用户显示预期响应正在加载。
查看 Pen
ojRMaN by Geoff Graham (@geoffgraham)
在 CodePen 上。
所有这些都可以使用名为 React Async 的库来完成。
React Async 是一个基于 Promise 的库,使您能够在 React 应用程序中获取数据。让我们看看使用组件、钩子和辅助函数的不同示例,以了解如何实现请求时的加载状态。
在本教程中,我们将使用 Create React App。您可以通过运行以下命令来创建项目
npx create-react-app react-async-demo
完成后,使用 yarn 或 npm 运行命令在您的项目中安装 React Async
## yarn
yarn add react-async
## npm
npm install react-async --save
示例 1:组件中的加载器
该库允许我们直接在 JSX 中使用 <Async>
。因此,组件示例将如下所示;
// Let's import React, our styles and React Async
import React from 'react';
import './App.css';
import Async from 'react-async';
// We'll request user data from this API
const loadUsers = () =>
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => (res.ok ? res : Promise.reject(res)))
.then(res => res.json())
// Our component
function App() {
return (
<div className="container">
<Async promiseFn={loadUsers}>
{({ data, err, isLoading }) => {
if (isLoading) return "Loading..."
if (err) return `Something went wrong: ${err.message}`
if (data)
return (
<div>
<div>
<h2>React Async - Random Users</h2>
</div>
{data.map(user=> (
<div key={user.username} className="row">
<div className="col-md-12">
<p>{user.name}</p>
<p>{user.email}</p>
</div>
</div>
))}
</div>
)
}}
</Async>
</div>
);
}
export default App;
首先,我们创建了一个名为 loadUsers
的函数。这将使用 fetch API 进行 API 调用。并且,当它完成时,它将返回一个已解析的 Promise。之后,将向组件提供必要的 props。
props 是
isLoading
:这处理服务器尚未收到响应的情况。err
:对于遇到错误的情况。您也可以将其重命名为error
。data
:这是从服务器获取的预期数据。
从示例中可以看出,我们返回了一些内容以显示给用户,具体取决于 props。
示例 2:钩子中的加载器
如果您是钩子的粉丝(如您所料),在使用 React Async 时有一个钩子选项可用。以下是它的样子
// Let's import React, our styles and React Async
import React from 'react';
import './App.css';
import { useAsync } from 'react-async';
// Then we'll fetch user data from this API
const loadUsers = async () =>
await fetch("https://jsonplaceholder.typicode.com/users")
.then(res => (res.ok ? res : Promise.reject(res)))
.then(res => res.json())
// Our component
function App() {
const { data, error, isLoading } = useAsync({ promiseFn: loadUsers })
if (isLoading) return "Loading..."
if (error) return `Something went wrong: ${error.message}`
if (data)
// The rendered component
return (
<div className="container">
<div>
<h2>React Async - Random Users</h2>
</div>
{data.map(user=> (
<div key={user.username} className="row">
<div className="col-md-12">
<p>{user.name}</p>
<p>{user.email}</p>
</div>
</div>
))}
</div>
);
}
export default App;
这看起来与组件示例类似,但在此场景中,我们使用的是 useAsync
而不是 Async
组件。响应返回一个已解析的 Promise,我们还可以访问与上一个示例中类似的 props,然后我们可以将其返回到呈现的 UI 中。
示例 3:辅助函数中的加载器
辅助组件在使代码清晰易读方面非常有用。这些辅助组件可以在使用 useAsync
钩子或 Async
组件时使用,我们刚才都介绍了它们。以下是如何使用 Async
组件与辅助组件一起使用的示例。
// Let's import React, our styles and React Async
import React from 'react';
import './App.css';
import Async from 'react-async';
// This is the API we'll use to request user data
const loadUsers = () =>
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => (res.ok ? res : Promise.reject(res)))
.then(res => res.json())
// Our App component
function App() {
return (
<div className="container">
<Async promiseFn={loadUsers}>
<Async.Loading>Loading...</Async.Loading>
<Async.Fulfilled>
{data => {
return (
<div>
<div>
<h2>React Async - Random Users</h2>
</div>
{data.map(user=> (
<div key={user.username} className="row">
<div className="col-md-12">
<p>{user.name}</p>
<p>{user.email}</p>
</div>
</div>
))}
</div>
)
}}
</Async.Fulfilled>
<Async.Rejected>
{error => `Something went wrong: ${error.message}`}
</Async.Rejected>
</Async>
</div>
);
}
export default App;
这看起来与我们使用 props 时类似。完成此操作后,您可以将应用程序的不同部分分解成微型组件。
结论
如果您已经厌倦了使用我在本教程开头部分提到的方法,您可以在您正在进行的项目中开始使用 React Async。本教程中使用的源代码可以在 GitHub 上的不同分支中找到。
我用过一段时间的一个库,我认为它有一个更好的模式:https://github.com/ctrlplusb/react-jobs
它尚未更新为使用或提供钩子,但它需要的样板代码更少,因为组件将在内部处理缓存、加载和错误状态。我有一个类似的组件,但它添加了“无结果”状态:https://github.com/unleashit/npm-library/tree/master/packages/asyncHandler(尽管我建议使用 react-jobs,因为它经过了更严格的验证,并且可以在服务器上运行)。
我对钩子还没有太多经验,但 HOC 的主要优势仍然是能够直接返回 JSX 并有选择地渲染其子元素。
非常好。我们在工作中使用 graphql/apollo,所以这并不真正需要,但对其他用途非常有帮助 :)
很棒的文章,我会尝试一下。