掌握ChatGPT插件与自定义GPT
通过Fetch和Axios在React中使REST API
如果您是一名 React 开发人员,想要学习如何在 React 应用中集成 API,这篇文章非常适合您。本文将介绍在 React 中使用 REST API 的两种最流行的方法:Fetch API 和 Axios。Shedrack Akintayo 将向您展示如何利用这些工具来构建一个简单的应用程序,并解释什么是 REST API。
在 React 应用程序中使用 REST API 可以通过多种方式完成,但在本教程中,我们将讨论如何使用两种最流行的方法来使用 REST API,即 Axios(基于 Promise 的 HTTP 客户端)和 Fetch API(浏览器内置的 Web API)。我会详细解释这两种方法,并展示它们一些很酷的功能。
API 是一种工具,可以帮助我们使用数据增强 React 应用程序。有些操作不能在客户端完成,因此这些操作是在服务器端实现的。然后,我们可以使用 API 在客户端使用数据。
API 由一组数据组成,这些数据通常采用 JSON 格式,具有指定的终端节点。当我们从 API 访问数据时,我们希望访问该 API 框架中的特定端点。我们也可以说 API 是两个服务之间关于请求和响应形式的合同协议。代码只是一个副产品。它还包含此数据交换的条款。
在 React 中,我们可以通过多种方式在应用程序中使用 REST API,这些方法包括使用 JavaScript 内置方法和 Axios,它是一个基于 Promise 的浏览器和Node.js HTTP 客户端。
注意:对 ReactJS、React Hooks、JavaScript 和 CSS 的良好了解将在你完成本教程时派上用场。
让我们开始了解有关 REST API 的更多信息。
什么是 REST API
REST API 是遵循根据 API 的 REST 结构构建内容的 API。REST 代表 “Representational State Transfer”。它由开发人员在创建 API 时遵循的各种规则组成。
REST API 的优势
- 非常容易学习和理解;
- 它使开发人员能够将复杂的应用程序组织成简单的资源;
- 外部客户端可以轻松地在您的 REST API 上构建,而不会出现任何复杂性;
- 它很容易扩展;
- REST API 不是特定于语言或平台的,但可以与任何语言一起使用或在任何平台上运行。
REST API 响应示例
REST API 的结构方式取决于它所针对的产品 ,但必须遵守 REST 的规则。
下面的示例响应来自 Github Open API。在本教程的后面部分,我们将使用此 API 构建 React 应用程序。
{
"login": "hacktivist123",
"id": 26572907,
"node_id": "MDQ6VXNlcjI2NTcyOTA3",
"avatar_url": "https://avatars3.githubusercontent.com/u/26572907?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/hacktivist123",
"html_url": "https://github.com/hacktivist123",
"followers_url": "https://api.github.com/users/hacktivist123/followers",
"following_url": "https://api.github.com/users/hacktivist123/following{/other_user}",
"gists_url": "https://api.github.com/users/hacktivist123/gists{/gist_id}",
"starred_url": "https://api.github.com/users/hacktivist123/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/hacktivist123/subscriptions",
"organizations_url": "https://api.github.com/users/hacktivist123/orgs",
"repos_url": "https://api.github.com/users/hacktivist123/repos",
"events_url": "https://api.github.com/users/hacktivist123/events{/privacy}",
"received_events_url": "https://api.github.com/users/hacktivist123/received_events",
"type": "User",
"site_admin": false,
"name": "Shedrack akintayo",
"company": null,
"blog": "https://sheddy.xyz",
"location": "Lagos, Nigeria ",
"email": null,
"hireable": true,
"bio": "☕ Software Engineer | | Developer Advocate🥑|| ❤ Everything JavaScript",
"public_repos": 68,
"public_gists": 1,
"followers": 130,
"following": 246,
"created_at": "2017-03-21T12:55:48Z",
"updated_at": "2020-05-11T13:02:57Z"
}
当我向以下端点发出请求时,上面的响应来自 Github REST API。它返回有关名为 hacktivist123 的用户的所有存储数据。有了这个响应,我们可以决定如何在 React 应用程序中展示这些信息。
利用 Fetch API 使用 API
API 是一种内置的 JavaScript 方法,用于从服务器或 API 端点获取资源。它类似于fetch()XMLHttpRequest,但 fetch API 提供了更强大、更灵活的功能集。
它定义了 CORS 和 HTTP Origin 标头语义等概念,并在其他位置取代了它们的单独定义。
API 方法始终采用强制参数,即要获取资源的路径或URL。它返回一个Promise对象,无论请求是否成功,这个Promise都会包含请求的响应。您还可以选择将 init options 对象作为第二个参数传入。
获取响应后,可以使用几种内置方法来定义响应正文的内容及其处理方式。
Fetch API 和 jQuery Ajax 之间的区别
Fetch API 与 jQuery Ajax 的主要区别在于三个方面,它们是:
- 当出现 HTTP 错误时,无论响应状态的性质如何,从请求返回的 Promise 都不会被拒绝。相反,它会正常解析请求,如果响应状态码是 400 或 500 类型的代码,它会设置 ok 状态。请求只会因为网络故障或某些因素阻止请求完成而被拒绝。
fetch()
将不允许使用跨站点 Cookie,即您不能使用fetch()
。fetch()
默认情况下也不会发送 Cookie,除非您在 init 中设置了credentials
选项。
Fetch API 的参数
resource
这是您要获取的资源的路径,可以是指向资源路径的直接链接,也可以是请求对象init
这是一个对象,其中包含您要为请求提供的任何自定义设置或凭证。以下是对象中可以包含的一些可能选项:method
这是为了指定 HTTP 请求方法,例如 GET、POST 等。headers
这用于指定要添加到请求中的任何标头,通常包含在对象或对象文本中。body
这是用于指定你想添加到请求的正文:这可以是 FormData、URLSearchParams、USVStringReadableStream 或其他格式。mode
这是用于指定你想要使用的请求模式的,例如 cors、no-cors 或 same-origin。credentials
此选项用于指定要用于请求的请求凭证,如果您考虑为当前域自动发送 Cookie,则必须提供此选项。
使用 fetch() API 的基本语法
一个基本的 fetch 请求写起来真的很简单,看看下面的代码:
fetch('https://api.github.com/users/hacktivist123/repos')
.then(response => response.json())
.then(data => console.log(data));
在上面的代码中,我们从以 JSON 格式返回数据的 URL 获取数据,然后将其打印到控制台。使用 fetch() 的最简单形式通常只接受一个参数,即你要获取的资源的路径,然后返回一个包含 fetch 请求响应的 promise。此响应是一个对象。
响应只是常规 HTTP 响应,而不是实际的 JSON。为了从响应中获取 JSON 正文内容,我们必须在响应上使用 json() 方法将响应更改为实际的 JSON。
在 React 应用程序中使用 Fetch API
在 React Apps 中使用 Fetch API 是我们通常在 javascript 中使用 Fetch API 的方式,语法没有变化,唯一的问题是决定在我们的 React 应用程序中的哪个位置发出 fetch 请求。大多数 fetch 请求或任何形式的 HTTP 请求通常是在 React 组件中完成的。
如果您的组件是 Class Component,则可以在 Lifecycle Method 中发出此请求,如果你的组件是一个 Functional Component,可以在React Hook中发起 。
例如,在下面的代码中,我们将在类组件中发出 fetch 请求,这意味着我们必须在生命周期方法中执行此操作。在这种特殊情况下,我们的 fetch 请求将在生命周期方法中发出,因为我们想在 React 组件挂载后立即发出请求。componentDidMount
好的,以下是调整后的句子:
例如,在下面的代码中,我们将在类组件中发出 fetch 请求。这意味着我们必须在生命周期方法中执行此操作。在这种情况下,我们的 fetch 请求将在生命周期方法 componentDidMount 中发出,因为我们想在 React 组件挂载后立即发出请求。
import React from 'react';
class myComponent extends React.Component {
componentDidMount() {
const apiUrl = 'https://api.github.com/users/hacktivist123/repos';
fetch(apiUrl)
.then((response) => response.json())
.then((data) => console.log('This is your data', data));
}
render() {
return <h1>my Component has Mounted, Check the browser 'console' </h1>;
}
}
export default myComponent;
在上面的代码中,我们正在创建一个非常简单的类组件,该组件发出一个 fetch 请求,在 React 组件完成挂载后,将我们对 API URL 发出的 fetch 请求的最终数据记录到浏览器控制台中。
该方法可以获取我们想要获取的资源的路径,该路径被分配给一个名为 fetch 请求。当请求完成后,它将返回一个包含 response 对象的 Promise。然后,我们使用该方法从响应中提取 JSON 正文内容,最后我们将 Promise 的最终数据记录到控制台中。
让我们使用 Fetch 方法的 REST API
在本节中,我们将构建一个使用外部 API 的简单 react 应用程序,我们将使用 Fetch 方法来使用 API。
这个简单的应用程序将显示属于特定用户的所有存储库及其描述。在本教程中,我将使用我的 GitHub 用户名,如果您愿意,您也可以使用您的用户名。
我们需要做的第一件事是使用create-react-app生成我们的React应用。
npx create-react-app myRepos
上面的命令将为我们引导一个新的 React 应用程序。创建新应用程序后,剩下要做的就是运行以下命令并开始编码:
npm start
如果我们的 React 创建正确,我们应该在运行上述命令后导航到浏览器窗口时看到localhost:3000
。
在您的文件夹中,创建一个名为srccomponent
的新文件夹。这个文件夹将保存我们所有的 React 组件。在新文件夹中,创建两个名为 List.js 和 withListLoading.js 的文件。这两个文件将保存我们的应用程序中需要的组件。
List.js 文件将以列表的形式处理 Repositories 的显示,而 withListLoading.js 文件将包含一个高阶组件,该组件将在我们将要发出的 Fetch 请求仍在进行时显示。
在我们List.js文件夹内创建的文件中,让我们粘贴以下代码:
import React from 'react';
const List = (props) => {
const { repos } = props;
if (!repos || repos.length === 0) return <p>No repos, sorry</p>;
return (
<ul>
<h2 className='list-head'>Available Public Repositories</h2>
{repos.map((repo) => {
return (
<li key={repo.id} className='list'>
<span className='repo-text'>{repo.name} </span>
<span className='repo-description'>{repo.description}</span>
</li>
);
})}
</ul>
);
};
export default List;
上面的代码是一个基本的 React 列表组件,它将在列表中显示数据,在本例中为存储库名称及其描述。
现在,让我一点一点地解释代码。
const { repos } = props;
我们正在为名为 repos 的组件初始化一个 prop。
if (repos.length === 0 || !repos) return <p>No repos, sorry</p>;
在这里,我们所做的只是制作一个条件语句,当我们从发出的请求中获得的存储库长度等于零时,该语句将呈现一条消息。
return (
<ul>
<h2 className='list-head'>Available Public Repositories</h2>
{repos.map((repo) => {
return (
<li key={repo.id} className='list'>
<span className='repo-text'>{repo.name} </span>
<span className='repo-description'>{repo.description}</span>
</li>
);
})}
</ul>
);
在这里,我们将映射我们发出的 API 请求将提供的每个存储库,并提取每个存储库名称及其描述,然后将每个存储库显示在列表中。
export default List;
在这里,我们导出了我们的组件,以便我们可以在其他地方使用它。
在我们 components 文件夹中创建的 withListLoading.js 文件中,让我们粘贴以下代码:
import React from 'react';
function WithListLoading(Component) {
return function WihLoadingComponent({ isLoading, ...props }) {
if (!isLoading) return <Component {...props} />;
return (
<p style={{ textAlign: 'center', fontSize: '30px' }}>
Hold on, fetching data may take some time :)
</p>
);
};
}
export default WithListLoading;
上面的代码是一个高阶 React 组件,它接受另一个组件作为参数,并返回一个新的组件。在这个例子中,高阶组件会等待检查传入的组件的状态是否为 true。如果状态为 true,它会显示一条消息 “Hold on, fetching data may take some time :)”。然后,它将状态更改为 false,并渲染传入的组件(在这个例子中是 List 组件)。
在 src 文件夹内的 *App.js 文件中,让我们粘贴以下代码:
import React, { useEffect, useState } from 'react';
import './App.css';
import List from './components/List';
import withListLoading from './components/withListLoading';
function App() {
const ListLoading = withListLoading(List);
const [appState, setAppState] = useState({
loading: false,
repos: null,
});
useEffect(() => {
setAppState({ loading: true });
const apiUrl = `https://api.github.com/users/hacktivist123/repos`;
fetch(apiUrl)
.then((res) => res.json())
.then((repos) => {
setAppState({ loading: false, repos: repos });
});
}, [setAppState]);
return (
<div className='App'>
<div className='container'>
<h1>My Repositories</h1>
</div>
<div className='repo-container'>
<ListLoading isLoading={appState.loading} repos={appState.repos} />
</div>
<footer>
<div className='footer'>
Built{' '}
<span role='img' aria-label='love'>
💚
</span>{' '}
with by Shedrack Akintayo
</div>
</footer>
</div>
);
}
export default App;
我们的 App.js 是一个功能组件,它使用 React Hooks 来处理状态和副作用。如果你不熟悉 React Hooks,请阅读我的 React Hooks 入门指南。
让我一点一点地解释上面的代码。
import React, { useEffect, useState } from 'react';
import './App.css';
import List from './components/List';
import withListLoading from './components/withListLoading';
在这里,我们将导入所需的所有外部文件,以及我们在 components 文件夹中创建的组件。我们还从 React 中导入了我们需要的 React Hooks。
const ListLoading = withListLoading(List);
const [appState, setAppState] = useState({
loading: false,
repos: null,
});
在这里,我们正在创建一个名为 ListLoading 的新组件,并分配我们的高阶组件。然后,我们创建了一个名为 loading 的状态值,并使用 React Hook useState() 来管理它。最后,我们将这个状态值传递给我们的高阶组件,以便在列表加载时显示相应的消息。
useEffect(() => {
setAppState({ loading: true });
const user = `https://api.github.com/users/hacktivist123/repos`;
fetch(user)
.then((res) => res.json())
.then((repos) => {
setAppState({ loading: false, repos: repos });
});
}, [setAppState]);
在这个 React Hook 中,我们首先将初始加载状态设为 true。当这个状态为 true 时,我们的高阶组件会显示一条消息。接着,我们创建一个名为 NAME 的常量变量,并将其设置为我们将从中获取存储库数据的 API URL。然后,我们使用 useEffect() 钩子来处理副作用。
然后,我们像上面讨论的那样发出一个基本请求,然后在请求完成后,我们将应用程序加载状态设置为 false,并使用我们从请求中获得的数据填充存储库状态。
return (
<div className='App'>
<div className='container'>
<h1>My Repositories</h1>
</div>
<div className='repo-container'>
<ListLoading isLoading={AppState.loading} repos={AppState.repos} />
</div>
</div>
);
}
export default App;
在这个示例中,我们渲染了一个高阶组件(HOC),它接收一个组件作为参数并返回一个新的组件。这个新的组件会使用传入的组件的 state 值来填充 prop 和 prop。同时,isLoadingrepos 这个 prop 用于指示数据是否正在加载。由于我们使用了 withListLoading HOC,所以在 fetch 请求仍在发出时,浏览器将显示相应的加载状态。
现在,当 fetch 请求成功完成时,我们应该会看到仓库以列表格式显示,如下所示:
现在,让我们稍微设置一下项目的样式,在您的 App.css 文件中,复制并粘贴此代码。
@import url('https://fonts.googleapis.com/css2?family=Amiri&display=swap');
:root {
--basic-color: #23cc71;
}
.App {
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
font-family: 'Amiri', serif;
overflow: hidden;
}
.container {
display: flex;
flex-direction: row;
}
.container h1 {
font-size: 60px;
text-align: center;
color: var(--basic-color);
}
.repo-container {
width: 50%;
height: 700px;
margin: 50px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
overflow: scroll;
}
@media screen and (max-width: 600px) {
.repo-container {
width: 100%;
margin: 0;
box-shadow: none;
}
}
.repo-text {
font-weight: 600;
}
.repo-description {
font-weight: 600;
font-style: bold;
color: var(--basic-color);
}
.list-head {
text-align: center;
font-weight: 800;
text-transform: uppercase;
}
.footer {
font-size: 15px;
font-weight: 600;
}
.list {
list-style: circle;
}
因此,在上面的代码中,我们通过为App.js文件中的各个元素分配不同的类名来设置应用程序的样式。这使得我们的应用程序看起来更加美观。
修改后,我们的应用程序应如下所示:
现在我们的应用程序看起来好多了。😊
在这段代码中,我们使用了 Fetch API 来调用 REST API。在下一节中,我们将探讨如何使用 Axios 库来实现相同的功能。
通过 Axios 使用 API
Axios 是一个易于使用的基于 Promise 的 HTTP 客户端,适用于浏览器和 node.js。由于 Axios 是基于 promise 的,我们可以利用 async 和 await 来获得更具可读性和异步的代码。使用 Axios,我们能够拦截和取消请求,它还具有内置功能,可提供客户端保护以防止跨站点请求伪造。
Axios 的特点
- 请求和响应拦截
- 简化的错误处理
- 针对 XSRF 的保护
- 支持上传进度
- 响应超时
- 取消请求的能力
- 支持较旧的浏览器
- 自动 JSON 数据转换
使用 Axios 发出请求
使用 Axios 发出 HTTP 请求非常简单。下面的代码基本上写出了如何发出 HTTP 请求。
// Make a GET request
axios({
method: 'get',
url: 'https://api.github.com/users/hacktivist123',
});
// Make a Post Request
axios({
method: 'post',
url: '/login',
data: {
firstName: 'shedrack',
lastName: 'akintayo'
}
});
上面的代码显示了我们使用 Axios 发出 GET 和 POST HTTP 请求的基本方法。
Axios 还提供了一组用于执行不同 HTTP 请求的速记方法。方法如下:
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
例如,如果我们想发出一个类似的请求,就像上面的示例代码一样,但使用简写方法,我们可以这样做:
// Make a GET request with a shorthand method
axios.get('https://api.github.com/users/hacktivist123');
// Make a Post Request with a shorthand method
axios.post('/signup', {
firstName: 'shedrack',
lastName: 'akintayo'
});
在上面的代码中,我们发出的请求与上面所做的相同,但这次使用简写方法。Axios 提供了灵活性,使您的 HTTP 请求更具可读性。
使用 Axios 发出多个请求
Axios 允许开发人员同时发出并处理多个 HTTP 请求。它通过 axios.all()
方法接受一个参数数组,并返回一个 promise 对象,该对象在所有传入的参数都解析完成后才会解析。
例如,我们可以使用以下方式向 GitHub API 发起多个请求:
axios.all([
axios.get('https://api.github.com/users/hacktivist123'),
axios.get('https://api.github.com/users/adenekan41')
])
.then(response => {
console.log('Date created: ', response[0].data.created_at);
console.log('Date created: ', response[1].data.created_at);
});
上面的代码通过 axios.all()
方法并行地向参数数组发出多个请求,并返回响应数据。在我们的示例中,它会将每个 API 响应中的对象记录到控制台。
让我们在 Axios 客户端中使用 REST API
在本节中,我们将使用 Axios 替换现有 React 应用程序中的 fetch() 方法。首先,我们需要安装 Axios,然后在 App.js 文件中使用它来向 GitHub API 发出 HTTP 请求。
现在让我们通过运行以下任一命令在我们的 React 应用程序中安装 Axios:
使用 NPM:
npm install axios
使用 Yarn:
yarn add axios
安装完成后,我们必须将 axios 导入到我们的 App.js 中。在我们的 App.js 中,我们将以下行添加到 App.js 文件的顶部:
import axios from 'axios'
添加代码行后,在 App.js 文件中,我们可以使用 useEffect()
钩子来处理副作用
useEffect(() => {
setAppState({ loading: true });
const apiUrl = 'https://api.github.com/users/hacktivist123/repos';
axios.get(apiUrl).then((repos) => {
const allRepos = repos.data;
setAppState({ loading: false, repos: allRepos });
});
}, [setAppState]);
您可能已经注意到,我们现在已将 fetch API 替换为 Axios 速记方法,以向 API 发出请求。
axios.get(apiUrl).then((repos) => {
const allRepos = repos.data;
setAppState({ loading: false, repos: allRepos });
});
在这个代码块中,我们发送一个 GET 请求以获取数据,并返回一个 Promise。这个 Promise 包含名为 repos
的数据,我们将这些数据分配给一个常量变量。然后,我们将当前的加载状态设置为 false,并将从请求中获得的数据传递给名为 repos
的状态变量。
如果我们正确地完成了所有操作,我们应该会看到我们的应用程序仍然以相同的方式呈现,没有任何变化。
这就是我们如何使用 Axios 客户端来使用 REST API的方法。
Fetch 与 Axios
在本节中,我将探讨 Fetch 和 Axios 对这些功能的支持程度。
- 基本语法
Axios 提供了更简洁的语法,自动将响应转换为 JSON,而 Fetch 需要手动转换。此外,Axios 的速记方法使得制作特定的 HTTP 请求更加容易。 - 浏览器兼容性
Axios 在主流浏览器和版本上都有很好的支持,而 Fetch 仅在 Chrome 42+、Firefox 39+、Edge 14+ 和 Safari 10.1+ 中受支持。 - 处理响应超时
Axios 通过使用请求对象中的选项轻松设置响应超时,而在 Fetch 中实现这一点较为困难。 - 拦截 HTTP 请求Axios
Axios 允许开发人员拦截 HTTP 请求,这对于需要在应用程序和服务器之间更改 HTTP 请求的情况非常有用。 - 同时发出多个请求
Axios 提供了发出多个 HTTP 请求的方法,而 Fetch 则需要额外的代码来实现这一功能。
结论
Axios 和 fetch 都是很好的 API 使用方法,但在构建小型应用程序时,建议使用 fetch,而在构建大型应用程序时,出于可扩展性考虑,推荐使用 Axios。希望这个教程对你有所帮助,如果你有任何问题,可以在下面的评论部分提问,我会很高兴回答每一个问题。
原文链接:https://www.smashingmagazine.com/2020/06/rest-api-react-fetch-axios/