使用 React Hooks 获取数据
React Hooks 是 React 的一个相对较新的功能,它允许我们将应用的状态保存在函数组件中,而无需创建类组件。根据React 关于 Hooks 的文档,处理数据获取的合适方式似乎是使用useEffect
Hooks。所以我就尝试这样做。
为了写这篇文章,我设想我想制作一个应用程序,从 API 中获取一本随机的书,将其显示为书籍推荐,并允许用户获得新的书籍推荐。
写一个useEffect
钩子
编写useEffect
相对简单。我们只需要创建一个函数组件并为其添加一些状态。
const BookApp = () => {
const [ book, setBook ] = useState({})
useEffect(() =>
fetch("BookApiUrl")
.then(res => res.json())
.then(setBook)
)
return(
<div>
<img src={book.cover} alt={`${book.title}'s cover page`} />
<p className="title">{book.title}</p>
<p className="author">{book.author}</p>
</div>
)
}
现在,不要在家尝试这个。如果你这样做,你会陷入无限循环。不过别担心,我们稍后会解决这个问题。这useEffect
将在组件完成挂载时以及每次状态发生变化时执行。这就是为什么我们得到一个无限循环。它从一个虚构的 API 获取数据,然后更新状态,然后状态变化触发另一个调用,useEffect
依此类推。
除此之外,就没什么有趣的事情了。通常情况下fetch
,我们会从 API 获取数据,然后对数据进行 JSON 化。之后,我们会使用 hooksetBook
来更新状态。
停止无限循环
接下来要做的就是修复这个循环。useEffect
它接受两个参数。第一个是它要执行的函数。第二个是一个值数组。如果这些值在重新渲染之间没有发生变化,React 将跳过该效果。
const BookApp = () => {
const [ book, setBook ] = useState({})
const [ count, setCount ] = useState(0)
useEffect(() =>
fetch("BookApiUrl")
.then(res => res.json())
.then(setBook),
[count])
return(
<div>
<img src={book.cover} alt={`${book.title}'s cover page`} />
<p className="title">{book.title}</p>
<p className="author">{book.author}</p>
<button onClick={() => setCount(count + 1)}>Get another book</button>
</div>
)
}
这绝对不是一个非常优雅的解决方案,但这是我首先想到的。我稍后会做一些改进。现在,我们的代码useEffect
只有在重新渲染之间发生变化时才会执行count
。其他状态变化不会触发其他数据获取。由于状态只有在用户点击按钮时才会发生变化,所以只有点击按钮才会触发效果(好吧,还有组件挂载)。
提示:如果您想模仿 的行为
componentDidMount
,只需添加一个空数组作为第二个参数即可。这样可以防止useEffect
在任何状态更改时执行。useEffect(() => { do stuff }, [])
使其更加优雅
我觉得,一个状态变量的唯一作用就是在按钮被点击时发生变化,这在我看来并不是一个特别好的解决方案。目前来看,还有另一个问题:API 可能会连续两次返回同一本书。理想情况下,我们希望避免这种情况。所以,让我们把两者结合起来,让代码更美观一些。
我不会使用计数器来计算按钮被点击的次数,而是将上一本书存储在应用程序的状态中,并检查在获取数据时是否得到相同的结果。
const BookApp = () => {
const [ book, setBook ] = useState({})
const [ lastBook, setLastBook ] = useState("")
useEffect(() => {
const fetchBook = () =>
fetch("BookApiUrl")
.then(res => res.json())
.then(data => {
if (data.title == lastBook) return fetchBook()
else setBook(data)
})
fetchBook()
}, [lastBook])
return(
<div>
<img src={book.cover} alt={`${book.title}'s cover page`} />
<p className="title">{book.title}</p>
<p className="author">{book.author}</p>
<button onClick={() => setLastBook(book.title)}>Get another book</button>
</div>
)
}
现在,告诉 effect hook 何时执行的状态也起到了跟踪上次检索到的书籍并避免再次检索的作用。需要注意的一个变化是,由于现在获取数据的函数可能是递归的,因此它需要一个名称以便能够调用自身。
概括
如果我们需要从 React 应用中的 API 获取数据,我们可以将获取操作放在 effect hook 中。不过,我们需要注意不要设置无限循环。我们需要在 state 中添加一些方法来告诉 hook 何时执行。除此之外,它与普通的fetch
.