原文:How To Use Axios With React: The Definitive Guide (2021),作者:Reed Barger

在本指南中,你将看到如何使用Axios.js和React,其中包括大量具有React hook的真实世界的例子。

你会看到为什么你应该使用Axios作为数据获取库,如何用React设置它,并使用它执行各种类型的HTTP请求。

然后,我们将触及更多的高级功能,例如创建Axios实例以实现可重用性、使用async-await来简化Axios,以及如何将Axios作为一个自定义Hook。

让我们直接开始吧!

想要自己的副本?‬ 📄

点击这里下载PDF格式的小册子(只需要5秒就能下载它)。

它包括这里所有的基本信息,是一个方便的PDF指南。

目录

什么是Axios?

Axios是一个HTTP客户端库,它允许你向一个给定的端点(endpoint)发出请求。

Screen-Shot-2021-07-12-at-1.14.41-PM

例如,这可能是一个外部API或你自己的后端Node.js服务器。

通过提出请求,你希望你的API能根据你提出的请求执行操作。

例如,如果你提出一个GET请求,你希望得到的数据能在你的应用程序中显示。

为什么在React中使用Axios

有许多不同的库可以用来提出这些请求,那么为什么选择Axios呢?

以下五个理由说明了为什么你应该使用Axios作为你的客户端来进行HTTP请求。

  1. 它有很好的默认值来处理JSON数据。与Fetch API等可选项不同,你通常不需要设置你的头文件。或执行繁琐的任务,如将你的请求体转换为JSON字符串
  2. Axios有与任何HTTP方法相匹配的函数名称。要执行一个GET请求,你可以使用.get()方法。
  3. Axios用更少的代码做更多的事情。与Fetch API不同,你只需要一个.then()回调来访问你请求的JSON数据。
  4. Axios有更好的错误处理。Axios为你抛出400和500范围的错误。不像Fetch API,你必须检查状态代码并自己抛出错误。
  5. Axios既可以在服务器上使用,也可以在客户端使用。如果你正在写一个Node.js应用程序,请注意Axios也可以在独立于浏览器的环境中使用。

如何用React设置Axios

在React中使用Axios是一个非常简单的过程。你需要三样东西:

  1. 一个现有的React项目
  2. 用npm/yarn来安装Axios
  3. 一个用于发出请求的API端点

创建一个新的React应用程序的最快捷的方法是访问react.new网站。

如果你有一个现有的React项目,你只需要用npm(或任何其他包管理器)安装Adios。

npm install axios

在本指南中,你将使用JSON Placeholder API来获取和改变帖子数据。

下面是你可以提出请求的所有不同路由(routes)的列表,以及每个路线的相应HTTP方法:

Screen-Shot-2021-07-10-at-12.21.28-PM

下面是一个快速的例子,说明你将使用Axios和你的API端点(endpoint)进行的所有操作——检索、创建、更新和删除帖子:

axios-react

如何进行GET请求(检索数据)

要获取数据或检索数据,要提出一个GET请求。

首先,你要对单个帖子进行请求。如果你看一下端点(endpoint),你将从/posts端点获得第一个帖子。

import axios from "axios";
import React from "react";

const baseURL = "https://jsonplaceholder.typicode.com/posts/1";

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() => {
    axios.get(baseURL).then((response) => {
      setPost(response.data);
    });
  }, []);

  if (!post) return null;

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </div>
  );
}

为了在挂载组件时执行这个请求, 你可以使用useEffectHook。这涉及到导入Axios,使用.get()方法向你的端点(endpoint)发出GET请求,并使用.then()回调获得所有的响应数据。

响应被作为一个对象返回。数据(这里是一个带有id,titlebody属性的帖子)被放在一个叫做post的状态中,在组件中显示。

请注意,你总是可以从响应中的.data属性中找到请求的数据。

如何进行POST请求(创建数据)

要创建新的数据,要发出一个POST请求。

根据API,这需要在/posts端点(endpoint)上执行。如果你看一下下面的代码,你会发现点击一个按钮可以创建一个帖子。

import axios from "axios";
import React from "react";

const baseURL = "https://jsonplaceholder.typicode.com/posts";

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() => {
    axios.get(`${baseURL}/1`).then((response) => {
      setPost(response.data);
    });
  }, []);

  function createPost() {
    axios
      .post(baseURL, {
        title: "Hello World!",
        body: "This is a new post."
      })
      .then((response) => {
        setPost(response.data);
      });
  }

  if (!post) return "No post!"

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
      <button onClick={createPost}>Create Post</button>
    </div>
  );
}

当你点击按钮时,它会调用createPost函数。

为了用Axios进行POST请求,你使用.post()方法。作为第二个参数,你包括一个对象属性,指定你希望新的帖子是什么。

再一次,使用.then()回调来获取响应数据,用你请求的新帖子替换你得到的第一个帖子。

这与.get()方法非常相似,但你想要创建的新资源是作为API端点(endpoint)之后的第二个参数提供的。

如何进行PUT请求(更新数据)

要更新一个给定的资源,要提出一个PUT请求。

在这种情况下,你将更新第一个帖子。

为了做到这一点,你将再次创建一个按钮。但这一次,该按钮将调用一个函数来更新一个帖子:

import axios from "axios";
import React from "react";

const baseURL = "https://jsonplaceholder.typicode.com/posts";

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() => {
    axios.get(`${baseURL}/1`).then((response) => {
      setPost(response.data);
    });
  }, []);

  function updatePost() {
    axios
      .put(`${baseURL}/1`, {
        title: "Hello World!",
        body: "This is an updated post."
      })
      .then((response) => {
        setPost(response.data);
      });
  }

  if (!post) return "No post!"

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
      <button onClick={updatePost}>Update Post</button>
    </div>
  );
}

在上面的代码中,你使用了Axios的PUT方法。和POST方法一样,你包括了你想在更新资源中的属性。

同样,使用.then()回调,你用返回的数据更新JSX。

如何进行DELETE请求(删除数据)

最后,要删除一个资源,使用DELETE方法。

作为一个例子,我们将删除第一个帖子。

注意,你不需要第二个参数来执行这个请求。

import axios from "axios";
import React from "react";

const baseURL = "https://jsonplaceholder.typicode.com/posts";

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() => {
    axios.get(`${baseURL}/1`).then((response) => {
      setPost(response.data);
    });
  }, []);

  function deletePost() {
    axios
      .delete(`${baseURL}/1`)
      .then(() => {
        alert("Post deleted!");
        setPost(null)
      });
  }

  if (!post) return "No post!"

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
      <button onClick={deletePost}>Delete Post</button>
    </div>
  );
}

在大多数情况下,你不需要从.delete()方法中返回的数据。

但在上面的代码中,.then()回调仍被用来确保你的请求被成功处理。

在上面的代码中,一个帖子被删除后,用户会被提醒它被成功删除。然后,帖子数据被清除出状态,将其设置为初始值null

另外,一旦一个帖子被删除,就会在警告信息后立即显示文本“没有帖子”。

如何处理Axios的错误

如何处理Axios的错误?

如果在发出请求时出现了错误怎么办?例如,你可能传递了错误的数据,向错误的端点(endpoint)发出了请求,或者出现了网络错误。

为了模拟一个错误,你将向一个不存在的API端点(endpoint)发送一个请求:/posts/asdf.

这个请求将返回一个404状态代码。

import axios from "axios";
import React from "react";

const baseURL = "https://jsonplaceholder.typicode.com/posts";

export default function App() {
  const [post, setPost] = React.useState(null);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    // invalid url will trigger an 404 error
    axios.get(`${baseURL}/asdf`).then((response) => {
      setPost(response.data);
    }).catch(error => {
      setError(error);
    });
  }, []);
  
  if (error) return `Error: ${error.message}`;
  if (!post) return "No post!"

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </div>
  );
}

在这种情况下,Axios不会执行.then()回调函数,而是抛出一个错误并运行.catch()回调函数。

在这个函数中,我们正在获取错误数据,并将其放入状态,以提醒我们的用户注意错误。因此,如果我们有一个错误,我们将显示该错误信息。

在这个函数中,错误数据被放在状态中,用来提醒用户注意错误。所以,如果有一个错误,就会显示一个错误信息。

当你运行这段代码的时候,你会看到这样的文字, "Error: Request failed with status code 404".

如何创建一个Axios实例

如果你看一下前面的例子,你会发现有一个baseURL,你用它作为Axios执行这些请求的端点(endpoint)的一部分。

然而,为每一个请求不断地编写baseURL是有点乏味的。你能不能让Axios记住你使用的baseURL?因为它总是涉及一个类似的端点。

事实上,你可以。如果你用.create()方法创建一个实例,Axios会记住baseURL,以及你可能想为每个请求指定的其他值,包括消息头(header)。

import axios from "axios";
import React from "react";

const client = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com/posts" 
});

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() => {
    client.get("/1").then((response) => {
      setPost(response.data);
    });
  }, []);

  function deletePost() {
    client
      .delete("/1")
      .then(() => {
        alert("Post deleted!");
        setPost(null)
      });
  }

  if (!post) return "No post!"

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
      <button onClick={deletePost}>Delete Post</button>
    </div>
  );
}

上述配置对象中的一个属性是baseURL,你把端点(endpoint)传给它。

.create()函数返回一个新创建的实例,在本例中它被称为client

然后在未来,你可以使用所有与之前相同的方法,但你不必再将baseURL作为第一个参数。你只需要引用你想要的特定路由,例如,//1,等等。

如何使用Axios的Async-Await语法

在JavaScript(包括React应用程序)中使用promises的一大好处是async-await语法。

Async-await允许你不使用thencatch回调函数的情况下写出更简洁的代码。另外,使用async-await的代码看起来很像同步代码,而且更容易理解。

但你如何使用Axios的async-await语法呢?

在下面的例子中,获取了帖子,但仍有一个按钮可以删除该帖子:

import axios from "axios";
import React from "react";

const client = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com/posts" 
});

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() => {
    async function getPost() {
      const response = await client.get("/1");
      setPost(response.data);
    }
    getPost();
  }, []);

  async function deletePost() {
    await client.delete("/1");
    alert("Post deleted!");
    setPost(null);
  }

  if (!post) return "No post!"

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
      <button onClick={deletePost}>Delete Post</button>
    </div>
  );
}

然而在useEffect中,有一个async函数,叫做getPost

让它成为async允许你使用await关键字来解决(resolve)GET请求,并在下一行将该数据设置为状态,而不需要.then()回调。

注意,getPost函数在被创建后立即被调用。

此外,deletePost函数现在是async,这是使用await关键字的要求,它可以解决(resolve)它返回的promise(每个Axios方法都会返回一个promise来解决(resolve))。

在使用await关键字和DELETE请求后,用户会被提醒帖子被删除,并且帖子被设置为null

正如你所看到的,async-await极大地简化了代码,你可以非常容易地将其用于Axios。

如何创建一个自定义的 `useAxios` Hook

Async-await是一个简化代码的好方法,但你可以更进一步。

你可以用Axios创建你自己的自定义Hook,作为一个可重用的函数执行同样的操作,而不是使用useEffect在组件挂载时获取数据。

虽然你可以自己制作这个自定义Hook,但是有一个非常好的库可以给你一个自定义的useAxios钩子,叫做use-axios-client。

首先,安装该软件包:

npm install use-axios-client

要使用Hook本身,请在组件的顶部从use-axios-client导入useAxios

因为你不再需要useEffect,你可以删除React的导入。

import { useAxios } from "use-axios-client";

export default function App() {
  const { data, error, loading } = useAxios({
    url: "https://jsonplaceholder.typicode.com/posts/1"
  });

  if (loading || !data) return "Loading...";
  if (error) return "Error!";

  return (
    <div>
      <h1>{data.title}</h1>
      <p>{data.body}</p>
    </div>
  ) 
}

现在你可以在应用程序组件的顶部调用useAxios,传入你想要请求的URL,钩子会返回一个对象,其中包含你需要处理不同状态的所有值。loading, error和解决(resolved)的data

在执行这个请求的过程中,值loading将为真。如果有一个错误,你会想显示这个错误状态。否则,如果你有返回的数据,你可以在用户界面中显示它。

像这样的自定义Hook的好处是,它确实减少了代码,并从整体上简化了代码

如果你想用Axios获取更简单的数据,可以试试像这样的自定义useAxios钩子。

还有呢?

恭喜你!你现在知道如何使用一个最强大的HTTP客户端库来支持你的React应用了。你现在知道如何使用最强大的HTTP客户端库之一来支持你的React应用程序。

我希望你从本指南中收获了很多。

记住,你可以将本指南下载为PDF格式的手册,以备将来参考。

欢迎加入 React 训练营

React 训练营 这本书把你应该知道的关于学习React的所有知识,综合在一起,包括视频、手册,还有特别的奖金。

收取已经成为React专家百名开发者的消息。他们已经找到自己梦想的工作,并掌控自己的未来。

The React Bootcamp
请点击这里,当它开放时,你将得到通知