`useEffect()` 和 `async`

2025-06-10

`useEffect()` 和 `async`

如果您已经学习了传统的基于类的 React 组件,并且现在正尝试转向 Hooks,那么在此过程中可能会有一些事情让您感到困惑。

对我来说,需要花点功夫去研究的一个东西就是- 本质上是- 和/ 的useEffect()替代品的组合componentDidMountcomponentDidUpdatecomponentWillUnmountasyncawait

现状

常见场景:我们的应用加载完毕,屏幕上显示了一些内容,然后我们想要获取一些数据。我们不想因为 API 调用耗时过长而阻碍用户继续操作,或者让他们盯着空白屏幕。

componentDidMount

如果使用基于 React 类的组件,这就是我们解决这个问题的方法。它确保首先将实际的组件插入到 DOM 树中,然后再render()调用。

如果我们不需要发出 API 请求,那么组件将直接渲染到屏幕上。如果我们确实需要发出 API 请求,则应该在 内部进行componentDidMount()。此外,如果在收到 API 响应后我们必须更新 或setState(),那么这实际上会触发第二次渲染。

那么调用将会是这样的:

  • 组件挂载()
  • 使成为()
  • setState() [来自 componentDidMount() 内部]
  • 使成为()

即使进行了二次渲染,React 文档也指出用户不会看到中间状态。所以没有奇怪的闪烁 UI——这对我们来说是好事!然而,文档也建议谨慎使用,因为这种方式可能会导致性能问题。

更具体地说,任何需要插入树的 DOM 节点都属于这个位置,componentDidMount()即 。如果可以的话,React 建议state在 中constructor()而不是此处进行初始化。显然,这并不总是可行的,但这是他们的建议。

// src/api/index.js 
export default {
  async index() {
    const res = await fetch('https://my-json-server.typicode.com/Claim-Academy-JS/products/products')

    return await res.json()
  }
}

/* ------------------ */
import api from 'api'

async componentDidMount() {
  const products = await api.index()
  this.setState({ filteredProducts: products, products })
}
Enter fullscreen mode Exit fullscreen mode

这段代码展示了内部进行的 fetch 调用componentDidMount(),在本例中,对于我的项目,我需要进行这样的设置。这些产品需要插入到 DOM 树中,所以我进行了 fetch 调用并设置了状态。当然,async这两者都在componentDidMount()以及我导出的对象的index()方法上进行。然后在这两个方法中,我们得到await了结果。

useEffect()

现在有了 Hooks,更具体地说useEffect(),我们需要注意几件事。首先,我们必须理解useEffect()需要两个参数

第一个参数

  • 回调函数

第二个论点

  • 监视属性的变化 -> 然后触发提供的回调

因此,像往常一样,需要一个回调函数——这并不奇怪。如果我们忘记指定第二个参数,它可能会导致一些问题。如果没有提供第二个参数,useEffect()则无论更新什么,每次更新都会触发回调函数。此外,如果函数内部使用了setState()或setter 方法,回调函数就会陷入无限循环。useState()useEffect()

让我们看一下与前面的示例等效的代码,只是使用了useEffect()

  useEffect(() => {
    (async () => {
      const products = await api.index()
      setFilteredProducts(products)
      setProducts(products)
    })()
  }, [])

Enter fullscreen mode Exit fullscreen mode

这次你会看到里面有一个立即调用函数表达式(IIFE)。我们也可以给这个函数命名,然后在里面直接调用它。

  useEffect(() => {
    const fetchProducts = async () => {
      const products = await api.index()
      setFilteredProducts(products)
      setProducts(products)
    }
    fetchProducts()
  }, [])

Enter fullscreen mode Exit fullscreen mode

还要注意,我们实际上提供了一个回调函数,useEffect()并且必须在该回调函数中定义另一个函数并调用它。这是因为 fetch 调用返回了一个 Promise。因此,它useEffect()本身并不负责处理这个问题,而是由我们定义的函数来处理。

最后,第二个参数用于确保它useEffect()仅在特定时间运行。

我们在这里提供了[]第二个参数。这表示useEffect()“嘿,我只希望你在这个组件首次挂载时运行你的回调,仅此而已。” 通过使用,[]我们告知useEffect()你没有需要监视的属性,然后在这些属性发生变化时运行你的回调。只需运行一次。

[]作为第二个参数和没有第二个参数之间也有区别。如前所述,没有第二个参数时,它useEffect()会认为它应该在组件挂载时运行,然后在之后的每次更新时运行,无论状态发生什么变化。

如果我们希望每次特定状态发生变化时运行一个函数,您只需将其放在括号内,就像这样[somePropertyNameHere]

文章将被卸载

useEffect()我花了些时间才找到将和函数组合起来的方法async。令人惊讶的是,React 文档中根本没有关于这种情况的示例。我参考了几篇解释此问题的不同第三方文章,以确保我的思路正确。Robin Wieruch 写了一篇相关文章;这是我找到的第一篇关于这个主题的文章,也是比较好的文章之一。

非常高兴能够解决这个问题,因为尽管这是一个很奇怪的问题 - 但我仍然更喜欢 Hooks!

鏂囩珷鏉ユ簮锛�https://dev.to/stlnick/useeffect-and-async-4da8
PREV
序列化成本
NEXT
在生产环境中使用 Golang 并发应用程序概述。采取的步骤步骤 2:客户端实现(用于 HTTP 调用)结论