【问题标题】:useEffect not rerenderinguseEffect 不重新渲染
【发布时间】:2020-12-03 07:29:51
【问题描述】:

好的,我是使用 react useEffect 钩子的新手,我很困惑为什么我会遇到这个问题。我使用此代码从 Firebase API 获取并将其放入名为 tempDoc 的数组中:

const tempDoc = []
useEffect(() => {
  var docRef = db.collection("campaigns");
  docRef.get().then(function(querySnapshot) {
      querySnapshot.forEach(function(doc) {
        tempDoc.push({
          id: doc.id,
          ...doc.data()
        })
        setCampaigns(tempDoc)
      });
    })
    .catch(function(error) {
      console.log("Error getting documents: ", error);
    });
}, []);

在控制台中,它返回我想要的对象数组。我将数组映射到显示卡。例如,假设我的数组有 3 个对象。有时当组件渲染时,只显示 1 张卡片,但我可以在控制台中看到,所有 3 个对象都在我的数组中。有时所有 3 个都渲染,但是当我转到新页面并返回主屏幕时,只显示 1 张卡片。很困惑。

组件的呈现方式肯定发生了一些变化。我是 useEffect 的新手,所以我不确定。

【问题讨论】:

  • useEffect 钩子在组件渲染后 运行,事实上,它与渲染组件没有太大关系。您能否更新您的问题以包含Minimal, Complete, and Reproducible 组件代码示例?其他事情可能会影响渲染的内容。您在哪里控制台记录数据?
  • 添加您尝试用来渲染卡片的代码。
  • 您似乎在 querySnapshot.forEach 循环中运行 setCampaigns(tempDoc)。在该循环之后,您应该只运行一次。

标签: reactjs frontend use-effect


【解决方案1】:

问题

如果我不得不猜测,我会说你有 2 个问题:

  1. tempDoc 不是反应状态的一部分,它会在每个渲染周期重置
  2. 状态更新正在循环中排队,但不会从以前的状态更新。当多个状态更新在单个渲染周期中排队时,它们不会从前一个状态更新,它们会从前一个渲染周期的相同状态依次更新。

解决方案

使用功能状态更新来正确地将每个新文档排入队列。 tempDoc 数组可能不需要,您可以在处理文档数据时将其排入队列。

useEffect(() => {
  var docRef = db.collection("campaigns");
  docRef.get().then(function(querySnapshot) {
      querySnapshot.forEach(function(doc) {
        setCampaigns(campaigns => [
          ...campaigns, // <-- shallow copy previous state
          { // <-- add new doc element
            id: doc.id,
            ...doc.data(),
          }
        ]);
      });
    })
    .catch(function(error) {
      console.log("Error getting documents: ", error);
    });
}, []);

您也可以先映射查询快照并使用单个状态更新。 (感谢@ΔO'deltazero')

useEffect(() => {
  var docRef = db.collection("campaigns");
  docRef.get().then(function(querySnapshot) {
      setCampaigns(querySnapshot.map(doc => ({
        id: doc.id,
        ...doc.data(),
      })));
    .catch(function(error) {
      console.log("Error getting documents: ", error);
    });
}, []);

【讨论】:

  • 这仍然在 setCampaigns 内多次运行 forEach...
  • @ΔO'deltazero' 这在使用功能状态更新时很好。
  • 在循环时不会导致多次重新渲染吗?
  • @ΔO'deltazero' 不,来自渲染周期的所有入队状态更新都是异步批处理个渲染周期之间并为下一个返回使成为。如果循环是异步的,那么它们可能会在不同的渲染周期中排队(但任何排队的在同一周期中都会更新并重新渲染一次)。
  • 我明白了。所以它做了一些多余的承诺,但它们都在渲染之前解决了。很高兴知道
【解决方案2】:

问题已完美描述here by Drew Reese。我建议的解决方案是:

const [ campaigns, setCampaigns ] = useState([]) // I suppose you already have this line

useEffect(() => {
  db.collection("campaigns").get()
    .then(querySnapshot =>
      setCampaings(querySnapshot.map(doc => ({
        id: doc.id,
        ...doc.data()
      })))
    )
    .catch(error => 
      console.log("Error getting documents: ", error)
    )
}, [])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-06
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 1970-01-01
    • 2020-01-06
    • 2020-04-01
    • 2021-07-23
    相关资源
    最近更新 更多