您需要了解的有关 Axios 的所有信息
介绍
与 Fetch API 一样,Axios 是一个基于承诺的 HTTP 客户端,用于从浏览器向外部服务器发出请求。如果您使用过 jQuery,您可能已经知道它的$.ajax()函数,该函数已成为前端开发人员比原生 XML HTTP 请求 (XHR) 接口更受欢迎的选择。Axios 库包装了复杂的 XHR 语法,并提供了一种抽象且声明性的方式来从浏览器以及在节点环境中发出请求。
在之前的指南中,我们已经讨论了如何使用 Axios 发出 HTTP 请求,使用axios.get()函数从服务器获取数据,并使用axios.post()函数将数据发布到服务器。在本指南中,我们将更深入地了解 Axios 提供的其他酷炫功能。
发出并发 HTTP 请求
很多时候,你会遇到这样的情况:你必须从两个端点发出请求才能完成一项特定任务。假设你正在使用 CMS REST API,并且必须获取当前用户的数据以及该用户的权限。你可能会做类似下面这样的事情:
class User extends Component {
constructor(props) {
super(props);
this.state = {
user: {
data: {},
permissions: {}
}
};
}
getUserData = async () => {
try {
const {data} = await axios.get(`${ROOT_URL}/profile/${this.props.activeUserId}`);
return data;
} catch (err) {
console.log(err.message);
}
}
getPermissions = async () => {
try {
const {data} = await axios.get(`${ROOT_URL}/permissions/${this.props.activeUserId}`);
return data;
} catch (err) {
console.log(err.message);
}
}
async componentDidMount() {
const userData = await this.getUserData();
const userPermissions = await this.getPermissions();
this.setState(
user: {
data: userData,
permissions: userPermissions
}
);
}
render() {
// render the data
}
}
我们可以使用axios.all()函数同时调用端点,而不必发出两次请求。
class User extends Component {
// ...
getUserData = () => axios.get(`${ROOT_URL}/profile/${this.props.activeUserId}`);
getPermissions = () => axios.get(`${ROOT_URL}/permissions/${this.props.activeUserId}`);
async componentDidMount() {
try {
const [userData, userPermissions] = await axios.all([ this.getUserData(), this.getPermissions() ]);
this.setState(
user: {
data: userData.data,
permissions: userPermissions.data
}
);
}
catch (err) {
console.log(err.message);
}
}
// ...
}
请注意,我使用了async-await语法来使代码更具可读性,而不是使用.then()和.catch()来处理承诺。话虽如此,您更喜欢哪种语法完全取决于您,两者都可以完成相同的处理承诺的工作。
axios.all()接受一个 Axios 请求数组,并返回一个包含每个 Axios 请求响应的数组。这里的问题是,即使其中一个请求失败,默认情况下,所有其他请求也会失败,并且第一个失败请求的错误将记录在catch()块中。
为了解决这个问题,我们可以简单地从每个 Axios 请求的catch()块返回 null。因此,即使其中一个请求失败,它仍会认为axios.all()承诺已得到解决。失败请求的返回值将为null,因此我们需要额外检查返回数组中的数据是否为null。
class User extends Component {
// ...
getUserData = () => axios.get(`${ROOT_URL}/profile/${this.props.activeUserId}`).catch(err => null);
getPermissions = () => axios.get(`${ROOT_URL}/permissions/${this.props.activeUserId}`).catch(err => null);
async componentDidMount() {
try {
const [userData, userPermissions] = await axios.all([ this.getUserData(), this.getPermissions() ]);
this.setState(
user: {
data: userData && userData.data,
permissions: userPermissions && userPermissions.data
}
);
}
catch (err) {
console.log(err.message);
}
}
// ...
}
我们可以进一步重构上面的代码,如下:
class User extends Component {
constructor(props) {
super(props);
this.state = {
user: {
data: {},
permissions: {}
}
};
}
async componentDidMount() {
const URLs = [ `${ROOT_URL}/profile/${this.props.activeUserId}`, `${ROOT_URL}/permissions/${this.props.activeUserId}` ];
const requests = URLs.map(URL => axios.get(URL).catch(err => null));
try {
const [userData, userPermissions] = await axios.all(requests);
this.setState(
user: {
data: userData && userData.data,
permissions: userPermissions && userPermissions.data
}
);
}
catch (err) {
console.log(err.message);
}
}
render() {
// render the data
}
}
从 Axios Response 中使用数组
API 通常会返回一个包含数据对象的数组。例如,当您想要从 CMS 中检索所有帖子时。要使用该数组,我们必须使用 Array.map ()函数循环遍历响应,具体操作如下:
class Posts extends Component {
constructor(props) {
super(props);
this.state = { posts: [] }
}
async componentDidMount() {
try {
const {data} = await axios.get(`${ROOT_URL}/posts`);
this.setState({
posts: data
})
} catch (err) {
console.log(err.message)
}
}
render() {
return (
<div className="container">
{ this.state.posts && this.state.posts.length !== 0 ?
this.state.posts.map(post => <Card title={post.title}>{post.content}</Card>) :
<Loading/> }
</div>
);
}
}
Array.map ()函数迭代数组的每个元素并返回一个新数组;在我们的例子中,该数组包含 JSX 元素,即<Card />组件。请注意,这里我使用的是简写版本,更完整的实现如下:
// ...
render() {
return (
<div className="container">
{ this.state.posts && this.state.posts.length !== 0 ?
this.state.posts.map((post, index) => {
const { title, content } = post;
return <Card title={title}>{content}</Card>;
}) :
<Loading/> }
</div>
);
}
//..
对于数组中的每个元素,map()函数为我们提供了一个匿名函数,该函数接受两个参数:元素本身和一个可选的 index 参数,该参数包含当前元素的位置值。我们还可以在使用 JSX 返回数据之前对其进行一些转换。例如,我们可以将标题转换为大写,如下所示:
// ...
this.state.posts.map((post, index) => {
const { title, content } = post;
const transformedTitle = title.toUpperCase();
return <Card title={transformedTitle}>{content}</Card>;
})
//..
对于 JSX 中的条件渲染,您不能使用if-else块。因此,我们使用了三元运算符。还请注意,当我们尝试在浏览器中运行上述代码时,我们会在控制台中收到一条警告消息,内容为:数组或迭代器中的每个子元素都应具有唯一的“key”属性。
React 使用key prop 来跟踪数组中的项。在上面的示例中,this.state.posts.map()将生成一个数组,因此每个 JSX 元素都必须具有与之关联的 key prop。不包含key prop 将导致意外结果和错误。
在我们的例子中,如果我们没有在<Card />组件中指定key prop ,React 将不知道如何跟踪帖子,因此,当状态发生变化时,它将重新渲染整个数组,而不是更新更改。这是不可取的,因为它会影响应用程序的性能。因此,对于数组项,至少有一个唯一的键值(在我们的例子中是帖子 ID)很重要。
//...
this.state.posts.map((post, index) => {
const { id, title, content } = post;
return <Card key={id} title={title}>{content}</Card>;
})
//...
中止或取消 Axios 请求
如果不再需要数据,您还可以取消或中止请求。要取消请求,我们需要使用 CancelToken.source ()工厂方法创建取消令牌。假设我们想在用户从当前页面导航到另一个页面时取消请求,我们可以编写如下内容:
const NavBar = props => (
<Nav>
<NavItem onClick={() => props.navigate('/home') }> Home </NavItem>
<NavItem onClick={() => props.navigate('/about') }> About </NavItem>
<NavItem onClick={() => props.navigate('/contact') }> Contact </NavItem>
</Nav>
)
class Posts extends Component {
constructor(props) {
super(props);
this.state = { posts: [] }
}
navigate = url => {
// cancel the request
this.source.<span
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~