如何在 ReactJS 中从 API 获取数据
如今,如果没有 API,Web 开发似乎就不完整,因为我们构建的大多数网站都使用某种 API 来驱动功能或使用数据。在 JavaScript 中从 API 获取数据相当容易理解,但在 React 中,除了原生 JavaScript 中使用的其他获取数据的代码之外,useEffect hook 的用法可能会让你感到有些困惑。
我们在 React 中使用 useEffect hook 从 API 获取数据,方法是在 useEffect hook 内部获取数据,但为什么我们不能像在原生 JavaScript 中那样在 React 中获取数据呢?
你可以这样回答,因为它是 React 开发的。
嗯……这或许是个不错的答案。
让我们先像在原生 JavaScript 中一样获取数据,然后看看它的行为,并找出为什么要在 useEffect hook 中获取数据的原因。
问题
在 React 中,我们使用 `setState` 回调函数将从 API 获取的数据存储在状态中,因为状态便于使用 props 在子组件之间共享数据。
因此,我们创建了一个名为`info` 的状态,用于存储从 JSON 占位符 API(提供测试数据的 API)获取的数据,我们将使用 `fetch` API 来实现此目的。
下面我们所做的,是在fetchData函数中获取数据,并使用setInfo回调将该数据设置为info状态,然后在函数下方调用该函数,并在组件的返回语句中渲染从 API 获取的数据的title 属性 ( info.title )。
关键在于,在嵌入式编辑器中从左向右拖动到 App.jsx 文件,然后取消注释 fetchData() 函数回调下方的 console.log(info),你会在控制台中观察到异常行为。(之后你可以再次取消注释,因为这会占用大量 CPU 资源。)
你会注意到 console.log 正在运行一个无限循环,一遍又一遍地输出相同的内容,但这是为什么呢?
出现此问题的原因是组件被反复渲染,但为什么会陷入无限循环呢?
这是因为每当我们从 API 获取数据时,都会使用`setInfo`回调函数将其设置到状态信息中。我们知道,在 React 中,当状态改变时,组件会自动重新渲染,导致 fetch 请求再次获取数据并再次设置状态,从而再次渲染组件,这就是为什么控制台日志会无限循环的原因。这种情况也称为副作用,即我们在 React 的作用域之外执行了一些操作。
所以你可能会认为我们可以避免使用 state 来存储数据来解决这个问题,但这并非最佳实践,因为 state 是一个强大的功能,它允许你修改现有数据,并通过 props 将其传递给其他子组件。这意味着我们需要其他方法来解决这个问题。而useEffect hook 正是在这种情况下应运而生的。
使用效果钩子
useEffect hook 可以帮助我们在组件中执行一些副作用,例如获取数据、直接更新 DOM 等。useEffect
hook 接受两个参数:一个回调函数和一个依赖数组。useEffect(<function>, <dependency>)
虽然第二个参数是可选的,我们将在本文后面详细介绍它。
使用 useEffect 钩子获取数据
useEffect 内部的 fetch 请求看起来会像这样
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then(res => res.json())
.then(data => setState(data))
}, [])
useEffect hooks 的语法看起来非常简单明了,fetch 请求被包裹在 hook 中,而另一个参数可以有三个可能的输入:无、空数组以及包含 state、props 或两者的数组。
useEffect hook 总是在组件渲染完成后运行其内部的回调函数。这里,fetch 请求是在组件渲染完成后发起的,数据被获取并设置到 info 状态。之后的问题是,useEffect 是否需要再次运行,这取决于如下的依赖数组:
- 没有依赖数组——useEffect 会在它所在的组件每次渲染完成后运行回调函数。简单来说,回调函数依赖于组件的所有内容(状态、属性)。
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then(res => res.json())
.then(data => setState(data))
})
- 空依赖数组([]) - useEffect 只会在组件首次渲染后运行一次回调函数。简单来说,回调函数不依赖于任何组件。
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then(res => res.json())
.then(data => setState(data))
}, [])
- 已填充的依赖关系数组([state, props]) - useEffect 会在依赖关系数组中的 state/props 每次更新时运行回调函数。简单来说,回调函数依赖于特定的 state 和 props。
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then(res => res.json())
.then(data => setState(data))
}, [state, props])
解决方案
现在我们已经了解了 useEffect,接下来我们需要选择应该添加哪些内容作为依赖数组输入,以解决我们面临的问题。
问题在于,该组件被反复渲染,导致无限循环。
假设我们使用 useEffect 而不使用依赖数组,这并不能解决我们的问题,因为 useEffect 运行时状态仍然会被更新,这将导致无限循环,因为组件会再次渲染,从而导致状态再次更新。
所以解决办法是使用空的依赖数组,因为我们需要在组件渲染完成后获取数据。
是的,这就是我们之前遇到的问题的解决方案,正如你现在在控制台中看到的,没有无限循环了。
嗯……依赖数组的第三个输入(已填充的那个)呢?当某个状态或属性发生变化时,如果需要再次获取数据,就可以使用它。
希望您喜欢这篇文章。如果您有任何不明白的地方或者喜欢这篇文章,请在评论区告诉我。
文章来源:https://dev.to/adityasaini3/how-to-fetch-data-from-api-in-reactjs-g56