React是一个流行的前端库,开发者用它来创建应用程序。而且,如果你想建立生产就绪的应用程序,你将需要在某些时候将API集成到你的React应用程序。
每个想用React构建现代、稳健的网络应用的开发者都必须了解如何消费API来获取数据到他们的React应用中。
在这个初学者指南中,你将学习如何在React中消费RESTful API,包括获取、删除和添加数据。我们还将讨论消耗RESTful API的两种主要方式,以及如何用React钩子使用它们。
什么是REST API?
如果你曾经花过任何时间编程或研究编程,你可能会遇到 "API "这个术语。
API是应用编程接口的意思。它是一种媒介,允许不同的应用程序以编程方式相互通信并实时返回响应。
Roy Fielding在2000年将REST定义为一种架构风格和方法,常用于互联网服务的开发,如分布式超媒体系统。它是一个缩写,代表 "REpresentational State Transfer"。
当通过REST API提出请求时,它会向请求者或端点发送资源当前状态的表示。这种状态表示可以采取JSON(JavaScript Object Notation)、XML或HTML的形式。
JSON是最广泛使用的文件格式,因为它与语言无关,人类和机器都可以阅读:
比如说
[
{
"userId": 1,
"id": 1,
"title": "sunt excepturi",
"body": "quia et suscipit\nsuscipit recusandae consequuntur "
},
{
"userId": 1,
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint nihil"
}
]
如何在React中消耗REST API's
你可以通过各种方式在React应用程序中消费REST API,但在本指南中,我们将看一下两种最流行的方法。Axios(一个基于承诺的HTTP客户端)和Fetch API(一个浏览器内置的网络API)。
注意:要完全理解本指南,你应该熟悉JavaScript、React和React钩子,因为它们是本指南的核心。
在我们讨论如何消费API之前,重要的是要了解在React中消费API与在JavaScript中的做法有很大不同。这是因为这些请求现在是在React组件中完成的。
在我们的案例中,我们将使用功能组件,这意味着我们需要使用两个主要的React Hooks。
- useEffect Hook:在React中,我们在
useEffect()钩中执行API请求。它要么在应用加载时立即渲染,要么在达到特定状态后渲染。这就是我们要使用的一般语法:
useEffect(() => {
// data fetching here
}, []);
- useState 钩子:当我们请求数据时,我们必须准备一个状态,当数据被返回时,它将被存储在这个状态中。我们可以将其保存在一个状态管理工具中,如Redux,或保存在一个上下文对象中。为了保持简单,我们将把返回的数据存储在React的本地状态中:
const [posts, setPosts] = useState([]);
现在让我们进入本指南的主要内容,我们将学习如何使用JSONPlaceholder posts API获取、添加和删除数据。这些知识适用于任何类型的API,因为本指南是为初学者准备的。
如何使用Fetch API消耗API
Fetch API是一种JavaScript内置方法,用于从服务器或API端点检索资源。它是内置的,所以你不需要安装任何依赖性或包。
fetch() 方法需要一个强制参数,即你想获取的资源的路径或URL。然后它返回一个Promise,这样你就可以使用then() 和catch() 方法处理成功或失败。
一个基本的获取请求写起来非常简单,看起来像下面的代码。我们只是从一个以JSON格式返回数据的URL中获取数据,然后将其记录到控制台:
fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
.then(response => response.json())
.then(data => console.log(data));
默认的响应通常是一个普通的HTTP响应,而不是实际的JSON,但我们可以通过使用响应的json()方法来获得我们的输出为JSON对象。
如何在React中使用Fetch API执行GET请求
你可以使用HTTP GET方法从一个端点请求数据。
如前所述,Fetch API接受一个强制参数,即true。它还接受一个选项参数,这是可选的,特别是在使用GET方法时,这是默认的。但对于其他方法,如POST和DELETE,你需要将方法附加到选项数组中:
fetch(url, {
method: "GET" // default, so we can ignore
})
到目前为止,我们已经了解了事情的运作方式,所以让我们把我们所学到的一切放在一起,执行一个获取请求,从我们的API中获取数据。
同样,我们将使用免费的在线API JSONPlaceholder来获取一个帖子的列表到我们的应用程序。
import React, { useState, useEffect } from 'react';
const App = () => {
const [posts, setPosts] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
.then((response) => response.json())
.then((data) => {
console.log(data);
setPosts(data);
})
.catch((err) => {
console.log(err.message);
});
}, []);
return (
// ... consume here
);
};
我们在前面的代码中创建了一个状态来存储我们将从API中获取的数据,这样我们就可以在以后的应用程序中消费它。我们还将默认值设置为一个空数组:
const [posts, setPosts] = useState([]);
然后,主要的操作发生在useEffect状态中,这样,一旦应用程序加载,数据/帖子就会被取走。获取请求产生了一个承诺,我们可以接受或拒绝:
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts?_limit=10').then(
(response) => console.log(response)
);
}, []);
这个响应包含了大量的数据,如状态代码、文本和其他信息,我们需要在以后处理错误时拥有这些信息。
到目前为止,我们已经用.then() 处理了一个解析,但它返回了一个响应对象,这不是我们想要的。所以我们需要使用json() 方法将Response对象解析为JSON格式。这也会返回一个承诺,让我们使用第二个.then() 来获取实际数据:
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
.then((response) => response.json())
.then((data) => {
console.log(data);
setPosts(data);
});
}, []);
如果我们看一下控制台,我们会发现我们已经从我们的API中获取了10个帖子,我们也将其设置为我们先前指定的状态。
这并不完整,因为我们只处理了承诺的解析,而没有处理承诺的拒绝,我们将使用.catch() 方法来处理拒绝:
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
.then((response) => response.json())
.then((data) => {
console.log(data);
setPosts(data);
})
.catch((err) => {
console.log(err.message);
});
}, []);
到目前为止,我们已经看到了如何执行一个GET 请求。到目前为止,我们已经看到了如何执行一个 的请求,这可以通过在我们的数组中循环来轻松完成:
const App = () => {
// ...
return (
<div className="posts-container">
{posts.map((post) => {
return (
<div className="post-card" key={post.id}>
<h2 className="post-title">{post.title}</h2>
<p className="post-body">{post.body}</p>
<div className="button">
<div className="delete-btn">Delete</div>
</div>
</div>
);
})}
</div>
);
};
export default App;
如何在React中使用Fetch API执行POST请求
你可以使用HTTPPOST 方法从一个端点发送数据。它的工作原理与GET 请求类似,主要区别在于你需要在可选对象中添加该方法和两个额外的参数:
const addPosts = async (title, body) => {
await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
title: title,
body: body,
userId: Math.random().toString(36).slice(2),
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
.then((response) => response.json())
.then((data) => {
setPosts((posts) => [data, ...posts]);
setTitle('');
setBody('');
})
.catch((err) => {
console.log(err.message);
});
};
可能看起来很奇怪的主要参数是body和header。
主体包含了我们要传入API的数据,我们必须首先对其进行字符串化处理,因为我们是在向网络服务器发送数据。头部告诉我们数据的类型,这在消费REST API的时候总是一样的。我们还设置了保存新数据的状态,并将剩余的数据分配到数组中。
看一下我们创建的addPost() 方法,它期望这些数据来自一个表单或其他什么东西。在我们的案例中,我创建了一个表单,通过状态获得表单数据,然后在表单提交时将其添加到方法中:
import React, { useState, useEffect } from 'react';
const App = () => {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
// ...
const addPosts = async (title, body) => {
await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
title: title,
body: body,
userId: Math.random().toString(36).slice(2),
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
.then((response) => response.json())
.then((data) => {
setPosts((posts) => [data, ...posts]);
setTitle('');
setBody('');
})
.catch((err) => {
console.log(err.message);
});
};
const handleSubmit = (e) => {
e.preventDefault();
addPosts(title, body);
};
return (
<div className="app">
<div className="add-post-container">
<form onSubmit={handleSubmit}>
<input type="text" className="form-control" value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<textarea name="" className="form-control" id="" cols="10" rows="8"
value={body} onChange={(e) => setBody(e.target.value)}
></textarea>
<button type="submit">Add Post</button>
</form>
</div>
{/* ... */}
</div>
);
};
export default App;
如何在React中用Fetch API执行DELETE请求
你可以使用HTTPDELETE 方法从一个端点移除数据。它的工作原理与GET 请求类似,主要区别在于增加了方法:
const deletePost = async (id) => {
await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
method: 'DELETE',
}).then((response) => {
if (response.status === 200) {
setPosts(
posts.filter((post) => {
return post.id !== id;
})
);
} else {
return;
}
});
};
这在按钮被点击时被触发,我们得到按钮被点击的特定帖子的id 。然后我们从整个检索的数据中删除该数据。
这将从API中删除,但不会立即从UI中删除,这就是为什么我们也添加了一个过滤器来删除这些数据。对于循环中的每个项目,你的删除按钮将看起来像这样:
const App = () => {
// ...
return (
<div className="posts-container">
{posts.map((post) => {
return (
<div className="post-card" key={post.id}>
{/* ... */}
<div className="button">
<div className="delete-btn" onClick={() => deletePost(post.id)}>
Delete
</div>
</div>
</div>
);
})}
</div>
);
};
export default App;
如何在Fetch API中使用Async/Await
到目前为止,我们已经看到了如何使用promise语法正常地提出获取请求,这有时会让人困惑。然后是链式的问题。我们可以通过使用Async/await来避免.then() ,并写出更可读的代码。
要使用async/await,首先在函数中调用async 。然后在发出请求并期待响应时,在函数前面添加await 语法,以等待承诺与结果的结算。
当我们使用async/await时,我们所有的Fetch请求将看起来像这样:
import React, { useState, useEffect } from 'react';
const App = () => {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
const [posts, setPosts] = useState([]);
// GET with fetch API
useEffect(() => {
const fetchPost = async () => {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts?_limit=10'
);
const data = await response.json();
console.log(data);
setPosts(data);
};
fetchPost();
}, []);
// Delete with fetchAPI
const deletePost = async (id) => {
let response = await fetch(
`https://jsonplaceholder.typicode.com/posts/${id}`,
{
method: 'DELETE',
}
);
if (response.status === 200) {
setPosts(
posts.filter((post) => {
return post.id !== id;
})
);
} else {
return;
}
};
// Post with fetchAPI
const addPosts = async (title, body) => {
let response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
title: title,
body: body,
userId: Math.random().toString(36).slice(2),
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
});
let data = await response.json();
setPosts((posts) => [data, ...posts]);
setTitle('');
setBody('');
};
const handleSubmit = (e) => {
e.preventDefault();
addPosts(title, body);
};
return (
// ...
);
};
export default App;
如何用Fetch API处理错误
在这一节,我们将看看如何用传统方法和async/await来处理错误。
我们可以使用响应数据来处理Fetch API中的错误,或者当使用async/await时,我们可以使用try/catch语句。
让我们看看我们如何在Fetch API中典型地做到这一点:
const fetchPost = () => {
fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then((data) => {
console.log(data);
setPosts(data);
})
.catch((err) => {
console.log(err.message);
});
};
你可以在这里阅读更多关于Fetch API的错误。
而对于async/await,我们可以像这样使用try 和catch :
const fetchPost = async () => {
try {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts?_limit=10'
);
const data = await response.json();
setPosts(data);
} catch (error) {
console.log(error);
}
};
如何使用Axios来消耗API
Axios是一个基于承诺的HTTP客户端库,它使向REST端点发送异步HTTP请求变得简单。在我们的例子中,这个端点是JSONPlaceholder Posts API,我们将向其发出GET 、POST 和DELETE 请求。
如何安装和配置Axios实例
与Fetch API不同,Axios不是内置的,所以我们需要把它纳入我们的项目,以便使用它。
你可以通过运行以下命令将Axios添加到你的项目中:
npm install axios
一旦你成功地安装了Axios,我们就可以继续创建一个实例,这是可选的,但建议这样做,因为它可以让我们避免不必要的重复。
为了创建一个实例,我们使用.create() 方法,我们可以用它来指定信息,如URL和可能的头文件:
import axios from "axios";
const client = axios.create({
baseURL: "https://jsonplaceholder.typicode.com/posts"
});
如何使用Axios在React中执行GET请求
我们将使用我们先前声明的实例来执行GET请求。我们所要做的就是设置参数(如果有的话),并默认以JSON格式获取响应。
与Fetch API方法不同,声明该方法时不需要任何选项。我们只需将该方法附加到实例上并进行查询:
useEffect(() => {
client.get('?_limit=10').then((response) => {
setPosts(response.data);
});
}, []);
如何使用Axios在React中执行POST请求
如前所述,你可以使用POST 方法来发送数据到一个端点。它的功能与GET 请求类似,主要区别在于需要包含方法和一个选项来保存我们要发送的数据:
const addPosts = (title, body) => {
client
.post('', {
title: title,
body: body,
})
.then((response) => {
setPosts((posts) => [response.data, ...posts]);
});
};
如何用Axios在React中执行DELETE请求
我们可以使用delete方法来执行删除请求,该方法获取id ,并从API中删除它。我们还将使用过滤器方法将其从UI中删除,就像我们使用Fetch API方法那样:
const deletePost = (id) => {
client.delete(`${id}`);
setPosts(
posts.filter((post) => {
return post.id !== id;
})
);
};
如何在Axios中使用异步/等待
到目前为止,我们已经看到了如何使用promise语法进行Axios请求。但现在让我们看看如何使用async/await来编写更少的代码并避免.then() 链。
当我们使用async/await时,我们所有的Axios请求将看起来像这样:
import React, { useState, useEffect } from 'react';
const App = () => {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
const [posts, setPosts] = useState([]);
// GET with Axios
useEffect(() => {
const fetchPost = async () => {
let response = await client.get('?_limit=10');
setPosts(response.data);
};
fetchPost();
}, []);
// Delete with Axios
const deletePost = async (id) => {
await client.delete(`${id}`);
setPosts(
posts.filter((post) => {
return post.id !== id;
})
);
};
// Post with Axios
const addPosts = async (title, body) => {
let response = await client.post('', {
title: title,
body: body,
});
setPosts((posts) => [response.data, ...posts]);
};
const handleSubmit = (e) => {
e.preventDefault();
addPosts(title, body);
};
return (
// ...
);
};
export default App;
如何用Axios处理错误
对于基于承诺的Axios请求,我们可以使用.then() 和。catch ( )方法,但对于async/await,我们可以使用try...catch 块。这与我们实现Fetch API的方式非常相似,try...catch 块将看起来像这样:
const fetchPost = async () => {
try {
let response = await client.get('?_limit=10');
setPosts(response.data);
} catch (error) {
console.log(error);
}
};
你可以在这里阅读更多关于用Axios处理错误的信息。
Fetch API与Axios
你可能已经注意到了一些区别,但让我们把它们放在一个方便的表格里,这样我们就可以正确地比较Fetch和Axios。
这些区别将帮助你决定在具体项目中使用哪种方法,这些区别中包括:
| Axios | Fetch |
|---|---|
| Axios是一个独立的第三方软件包,安装简单。 | Fetch内置于大多数现代浏览器中。 不需要安装 ,因为如此。 |
| Axios使用 数据 属性。 | Fetch使用 body 属性。 |
| Axios数据包含 对象。 | Fetch的主体必须是 字符串化。 |
| 当状态为200且statusText为'OK'时,Axios请求被接受。 | 当 响应对象包含ok属性时,Fetch请求是OK的。 |
| Axios对JSON数据进行 自动转换。 | 在处理JSON数据时,Fetch是一个 两步的过程 --首先,提出实际的请求;其次,在响应中调用.json()方法。 |
| Axios允许 取消请求和请求超时。 | Fetch则不允许。 |
| Axios有 ,内置支持下载进度。 | Fetch不支持上传进度。 |
| Axios有 广泛的浏览器支持。 | 当状态为200且statusText为'OK'时,Axios请求被接受。Fetch只与Chrome 42+、Firefox 39+、Edge 14+和Safari 10.1+兼容。(这被称为向后兼容)。 |
总结
在本指南中,我们学习了如何在React中使用Fetch API或Axios来消费REST APIs。
这将帮助你开始使用React中的API消费,从那里你将能够以更复杂的方式消费数据,并以你选择的方式操纵你的API。