如果您是 React 新手,并且可能只尝试过构建待办事项和计数器应用程序,那么您可能还没有遇到过需要为您的应用程序提取数据的需求。您很可能会遇到需要执行此操作的时候,因为 React 应用程序最 适合 处理数据和状态的情况。
您可能需要处理的第一组数据可能会硬编码到您的 React 应用程序中,就像我们在来自我们 错误边界教程 的此演示中所做的那样。
查看 Kingsley Silas Chijioke (@kinsomicrote) 在 CodePen 上的 Pen error boundary 0。
如果您想处理来自 API 的数据怎么办?这就是本教程的目的。具体来说,我们将使用 Fetch API 和 axios 作为请求和使用数据的示例。
Fetch API
Fetch API 提供了一个获取资源的接口。我们将使用它从第三方 API 获取数据,并了解如何在从内部构建的 API 获取数据时使用它。
使用 Fetch 与第三方 API
查看 Kingsley Silas Chijioke (@kinsomicrote) 在 CodePen 上的 Pen React Fetch API Pen 1。
我们将从 JSONPlaceholder(一个用于测试的虚假在线 REST API)获取随机用户。让我们首先创建我们的组件并声明一些默认状态。
class App extends React.Component {
state = {
isLoading: true,
users: [],
error: null
}
render() {
<React.Fragment>
</React.Fragment>
}
}
网络请求数据时,必然会存在延迟。可能是几秒钟,也可能是几毫秒。无论哪种方式,在此延迟期间,最好让用户知道在请求处理期间正在发生某些事情。
为此,我们将使用 isLoading
来显示加载消息或请求的数据。当 isLoading
为 false
时,将显示数据,否则将在屏幕上显示加载消息。因此,render()
方法将如下所示
render() {
const { isLoading, users, error } = this.state;
return (
<React.Fragment>
<h1>Random User</h1>
// Display a message if we encounter an error
{error ? <p>{error.message}</p> : null}
// Here's our data check
{!isLoading ? (
users.map(user => {
const { username, name, email } = user;
return (
<div key={username}>
<p>Name: {name}</p>
<p>Email Address: {email}</p>
<hr />
</div>
);
})
// If there is a delay in data, let's let the user know it's loading
) : (
<h3>Loading...</h3>
)}
</React.Fragment>
);
}
代码基本上是这样做的
- 从应用程序状态中解构
isLoading
、users
和error
,这样我们就不必一直键入this.state
了。 - 如果应用程序遇到建立连接的错误,则打印一条消息
- 检查数据是否正在加载
- 如果未加载,则我们必须拥有数据,因此我们显示它
- 如果正在加载,则我们仍然需要处理它,并在应用程序工作时显示“加载中…”
为了使步骤 3-5 起作用,我们需要发出请求以从 API 获取数据。对于我们的示例,JSONplaceholder API 将派上用场。
fetchUsers() {
// Where we're fetching data from
fetch(`https://jsonplaceholder.typicode.com/users`)
// We get the API response and receive data in JSON format...
.then(response => response.json())
// ...then we update the users state
.then(data =>
this.setState({
users: data,
isLoading: false,
})
)
// Catch any errors we hit and update the app
.catch(error => this.setState({ error, isLoading: false }));
}
我们创建一个名为 fetchUser()
的方法,并使用它来执行您可能想到的操作:从 API 端点请求用户数据并为我们的应用程序获取它。Fetch 是一个基于 Promise 的 API,它返回一个响应对象。因此,我们使用 json()
方法获取存储在数据中的响应对象,并将其用于更新应用程序中用户的 state。我们还需要将 isLoading
的 state 更改为 false
,以便我们的应用程序知道加载已完成,并且可以渲染数据。
Fetch 基于 Promise 的事实意味着我们还可以使用 .catch()
方法捕获错误。遇到的任何错误都用作更新错误 state 的值。方便!
应用程序第一次渲染时,数据尚未接收——可能需要几秒钟。当应用程序 state 可以访问以进行更新和重新渲染时,我们希望触发方法以获取用户。React 的 componentDidMount()
是最适合此操作的地方,因此我们将 fetchUsers()
方法放在其中。
componentDidMount() {
this.fetchUsers();
}
使用 Fetch 与自有 API
到目前为止,我们已经了解了如何在应用程序中使用其他人的数据。但是,如果我们在使用自己的 API 中自己的数据怎么办?这就是我们现在要介绍的内容。
查看 Kingsley Silas Chijioke (@kinsomicrote) 在 CodePen 上的 Pen React Fetch API Pen 2。
我构建了一个 API,可在 GitHub 上使用。您获得的 JSON 响应已放置在 AWS 上——这就是我们将用于本教程的内容。
与之前一样,让我们创建我们的组件并设置一些默认状态。
class App extends React.Component {
state = {
isLoading: true,
posts: [],
error: null
}
render() {
<React.Fragment>
</React.Fragment>
}
}
我们循环遍历数据的方法将与之前使用的方法不同,但这仅仅是因为数据结构不同,这将有所不同。您可以在这里查看我们的数据结构 here 和我们从 JSONPlaceholder 获得的数据结构之间的区别。
以下是我们的 API 的 render()
方法的外观
render() {
const { isLoading, posts, error } = this.state;
return (
<React.Fragment>
<h1>React Fetch - Blog</h1>
<hr />
{!isLoading ? Object.keys(posts).map(key => <Post key={key} body={posts[key]} />) : <h3>Loading...</h3>}
</React.Fragment>
);
}
让我们分解一下逻辑
{
!isLoading ?
Object.keys(posts).map(key => <Post key={key} body={posts[key]} />)
: <h3>Loading...</h3>
}
当 isLoading
不为 true
时,我们返回一个数组,遍历它并将信息作为 props 传递给 Post 组件。否则,在应用程序工作时显示“加载中…”消息。与之前非常相似。
获取帖子的方法将类似于第一部分中使用的方法。
fetchPosts() {
// The API where we're fetching data from
fetch(`https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json`)
// We get a response and receive the data in JSON format...
.then(response => response.json())
// ...then we update the state of our application
.then(
data =>
this.setState({
posts: data,
isLoading: false,
})
)
// If we catch errors instead of a response, let's update the app
.catch(error => this.setState({ error, isLoading: false }));
}
现在,我们可以在 componentDidMount()
方法中调用 fetchPosts
方法
componentDidMount() {
this.fetchPosts();
}
在 Post 组件中,我们遍历接收到的 props 并渲染每个帖子的标题和内容
const Post = ({ body }) => {
return (
<div>
{body.map(post => {
const { _id, title, content } = post;
return (
<div key={_id}>
<h2>{title}</h2>
<p>{content}</p>
<hr />
</div>
);
})}
</div>
);
};
就是这样!现在我们知道了如何使用 Fetch API 从不同的来源请求数据并在应用程序中使用它。击个掌。✋
axios
好的,所以我们花了大量时间研究 Fetch API,现在我们将把注意力转向 axios。
与 Fetch API 一样,axios 也是我们可以在应用程序中发出数据请求的一种方式。axios 的亮点在于它允许您向 REST 端点发送异步请求。在 React 项目中使用 REST API 时,这非常有用,例如 无头 WordPress CMS。
关于 Fetch 是否比 axios 更好,反之亦然,一直存在争议。我们在这里不会深入探讨,因为,您可以为正确的工作选择正确的工具。如果您对各方观点感兴趣,可以阅读 here 和 here。
使用 axios 与第三方 API
查看 Kingsley Silas Chijioke (@kinsomicrote) 在 CodePen 上的 Pen React Axios 1 Pen。
与我们对 Fetch API 所做的一样,让我们首先从 API 请求数据。对于此示例,我们将从 Random User API 获取随机用户。
首先,我们像之前每次一样创建 App 组件
class App extends React.Component {
state = {
users: [],
isLoading: true,
errors: null
};
render() {
return (
<React.Fragment>
</React.Fragment>
);
}
}
想法仍然相同:检查加载是否正在进行,并渲染我们收到的数据或让用户知道事情仍在加载。
要向 API 发出请求,我们需要创建一个函数。我们将函数称为 getUsers()
。在其中,我们将使用 axios 向 API 发出请求。让我们在进一步解释之前看看它是什么样子。
getUsers() {
// We're using axios instead of Fetch
axios
// The API we're requesting data from
.get("https://randomuser.me/api/?results=5")
// Once we get a response, we'll map the API endpoints to our props
.then(response =>
response.data.results.map(user => ({
name: `${user.name.first} ${user.name.last}`,
username: `${user.login.username}`,
email: `${user.email}`,
image: `${user.picture.thumbnail}`
}))
)
// Let's make sure to change the loading state to display the data
.then(users => {
this.setState({
users,
isLoading: false
});
})
// We can still use the `.catch()` method since axios is promise-based
.catch(error => this.setState({ error, isLoading: false }));
}
与 Fetch 示例非常不同,对吧?基本结构实际上非常相似,但现在我们正在处理端点之间的数据映射。
GET 请求作为参数从 API URL 传递。我们从 API 获取的响应包含一个名为 data
的对象,该对象包含其他对象。我们想要的信息在 data.results
中可用,它是一个包含单个用户数据的对象的数组。
我们再次在 componentDidMount()
方法中调用我们的方法
componentDidMount() {
this.getUsers();
}
或者,您可以执行此操作,并将这两步基本合并
componentDidMount() {
axios
.get("https://randomuser.me/api/?results=5")
.then(response =>
response.data.results.map(user => ({
name: `${user.name.first} ${user.name.last}`,
username: `${user.login.username}`,
email: `${user.email}`,
image: `${user.picture.thumbnail}`
}))
)
.then(users => {
this.setState({
users,
isLoading: false
});
})
.catch(error => this.setState({ error, isLoading: false }));
}
如果您是从您的机器本地编码,则可以暂时编辑 getUsers()
函数使其如下所示
getUsers() {
axios
.get("https://randomuser.me/api/?results=5")
.then(response => console.log(response))
.catch(error => this.setState({ error, isLoading: false }));
}
您的控制台应该会得到类似于此的内容

我们遍历 results 数组以获取每个用户所需的信息。然后,用户数组用于为我们的 users
state 设置新值。完成此操作后,我们就可以更改 isLoading
的值了。
默认情况下,isLoading
设置为 true
。当 users
的状态更新时,我们希望将 isLoading
的值更改为 false
,因为这是我们的应用程序用来从“加载中…”切换到渲染数据的提示。
render() {
const { isLoading, users } = this.state;
return (
<React.Fragment>
<h2>Random User</h2>
<div>
{!isLoading ? (
users.map(user => {
const { username, name, email, image } = user;
return (
<div key={username}>
<p>{name}</p>
<div>
<img src={image} alt={name} />
</div>
<p>{email}</p>
<hr />
</div>
);
})
) : (
<p>Loading...</p>
)}
</div>
</React.Fragment>
);
}
如果将 users
状态记录到控制台,您会发现它是一个对象数组。

空数组显示在获取数据之前的值。返回的数据仅包含各个用户的 name
、username
、email address
和 image
,因为这些是我们映射出的端点。当然,API 中还有更多可用数据,但我们必须将它们添加到我们的 getUsers
方法中。
使用 Axios 与您自己的 API
查看 Kingsley Silas Chijioke(@kinsomicrote)在 CodePen 上的笔 React Axios 2 Pen。
您已经了解了如何将 Axios 与第三方 API 结合使用,但我们可以看看从我们自己的 API 请求数据的情况,就像我们使用 Fetch API 所做的那样。事实上,让我们使用与 Fetch 使用的相同的 JSON 文件,以便我们可以看到这两种方法之间的区别。
以下是所有内容的组合。
class App extends React.Component {
// State will apply to the posts object which is set to loading by default
state = {
posts: [],
isLoading: true,
errors: null
};
// Now we're going to make a request for data using axios
getPosts() {
axios
// This is where the data is hosted
.get("https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json")
// Once we get a response and store data, let's change the loading state
.then(response => {
this.setState({
posts: response.data.posts,
isLoading: false
});
})
// If we catch any errors connecting, let's update accordingly
.catch(error => this.setState({ error, isLoading: false }));
}
// Let's our app know we're ready to render the data
componentDidMount() {
this.getPosts();
}
// Putting that data to use
render() {
const { isLoading, posts } = this.state;
return (
<React.Fragment>
<h2>Random Post</h2>
<div>
{!isLoading ? (
posts.map(post => {
const { _id, title, content } = post;
return (
<div key={_id}>
<h2>{title}</h2>
<p>{content}</p>
<hr />
</div>
);
})
) : (
<p>Loading...</p>
)}
</div>
</React.Fragment>
);
}
}
此方法与使用 Axios 从第三方获取数据之间的主要区别在于数据的格式。我们以这种方式直接获取 JSON,而不是映射端点。
我们从 API 获取的帖子数据用于更新组件的 posts
状态的值。有了这个,我们可以在 render()
中遍历帖子数组。然后,我们使用 ES6 解构获取每个帖子的 id
、title
和 content
,然后将其渲染给用户。
就像我们之前做的那样,显示的内容取决于 isLoading
的值。当我们使用从 API 获取的数据为 posts
设置新状态时,我们也必须为 isLoading
设置新状态。然后我们终于可以告知用户数据正在加载或渲染我们收到的数据。
async 和 await
Axios 基于 Promise 的特性允许我们做的另一件事是利用 async
和 await
。使用此功能,getPosts()
函数将如下所示。
async getPosts() {
const response = await axios.get("https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json");
try {
this.setState({
posts: response.data.posts,
isLoading: false
});
} catch (error) {
this.setState({ error, isLoading: false });
}
}
基本实例
使用 Axios,可以创建一个基本实例,在其中输入我们 API 的 URL,如下所示。
const api = axios.create({
baseURL: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json"
});
…然后像这样使用它。
async getPosts() {
const response = await api.get();
try {
this.setState({
posts: response.data.posts,
isLoading: false
});
} catch (error) {
this.setState({ error, isLoading: false });
}
}
这只是抽象 API URL 的一种好方法。
现在,获取所有数据!
在构建 React 应用程序时,您会遇到许多需要处理 API 数据的场景。希望您现在已经做好准备,可以使用各种来源的数据,并可以选择如何请求它。
想要处理更多数据?Sarah 最近写了一篇关于从公共 API 列表中 创建您自己的无服务器 API 的步骤的文章。
不错的教程!!!顺便说一句,在异步示例中,await 应该放在 try 块内。
谢谢 Viral,我会看看的。
我不太了解 Fetch,但我认为它无法执行请求和响应拦截器之类的事情,这在执行授权所有请求等操作时非常宝贵。Fetch 具有原生优势,因此无需加载额外的库,但听起来它要简单得多。
为什么检查
!isLoading
-> “显示数据”: “显示加载”。为什么不反过来使代码更易读:isLoading
-> “显示加载”: “显示数据”感谢此信息。例如,如果我在获取地址中强制出现错误,我似乎无法显示 error.message?