【问题标题】:Why my React app runs firebase query in useEffect when I alter the database?当我更改数据库时,为什么我的 React 应用程序在 useEffect 中运行 firebase 查询?
【发布时间】:2021-05-14 07:44:03
【问题描述】:

我的代码应该在第一次渲染时加载数据,所以我在 useEffect 中从 firebase 获取文档并将它们存储在状态“数据”中。它工作正常,所有文档都按我想要的方式显示在页面上。现在我想通过单击每个文档下的按钮来删除单个文档。我在 deleteDoc 函数的帮助下这样做了,该函数从数据库中删除文档(如果存在,则从存储中删除文件)。删除工作正常,但删除成功后,我的代码由于某种原因再次从数据库重新加载数据,导致应用程序再次重新呈现页面。我在 useEffect 中的 2 个不同位置进行控制台登录,发现 useEffect 不会执行其中的整个代码,而只会执行它从 firebase 获取数据的部分。我只是希望它在后台执行该操作,而不会再次干扰数据状态。那么,如何在每次删除文档时停止重新获取呢?

 const [data, setData] = useState([]);

 useEffect(() => {
    if (user) {
      user.getIdTokenResult().then((idTokenResult) => {
        setAdmin(idTokenResult.claims.admin);
      });

      db.collection("files")
        .orderBy("timeStamp", "desc")
        .limit(5)
        .onSnapshot((snapshot) => {
          console.log(data, "In query"); // This executes after the delete operation
          setData(
            snapshot.docs.map((doc) => {
              return [doc.data(), { doc_id: doc.ref.id }];
            })
          );
        });
    }

    console.log(data, "Outside query"); // This doesn't execute after the delete operation
   }, []);

删除函数:

 const deleteDoc = async (e, item) => {
    e.preventDefault();

    // Deleting file from storage if it exists
    if (item[0].file_name) {
      const deleteTask = storage
        .ref("users/" + user.uid)
        .child(item[0].file_name);

      deleteTask
        .delete()
        .then(() => {
          console.log("File deleted Successfully");
        })
        .catch((err) => console.log(err));
    }
     
    // Deleting document from firestore collection.
    db.collection("files")
      .doc(item[1].doc_id)
      .delete()
      .then(() => {
        setData(
          data.filter((doc) => {
            return doc[1].doc_id !== item[1].doc_id;
          })
        );
        console.log("Document successfully deleted!", data);
      })
      .catch((error) => {
        console.error("Error removing document: ", error);
      });
  };

【问题讨论】:

    标签: javascript reactjs firebase google-cloud-firestore


    【解决方案1】:

    通过调用 onSnapshot 从 Firestore 获取数据,您将附加一个永久侦听器 listens for realtime updates。因此,当数据库更改时,确实可以再次调用您的回调(从而再次更新状态)。

    如果您只想get the data once,请使用get() 而不是onSnapshot()

    db.collection("files")
      .orderBy("timeStamp", "desc")
      .limit(5)
      .get().then((snapshot) => {
        ...
    

    【讨论】:

    • 嘿,非常感谢!有效。我不知道永久听众。只需要注意一件事:get() 返回一个承诺,所以我不得不使用“.get().then((snapshot) => { ... })” 并且它起作用了。
    • 两个都完成了! ?再次感谢!
    【解决方案2】:

    根据这个document,我们可以使用onSnapshot监听集合中的变化,所以当你删除数据库中的文档时,onSnapshot将监听新的变化并在该函数中执行逻辑。

    解决方案是分离监听器

    const unsubscribe = db.collection("files")
        .orderBy("timeStamp", "desc")
        .limit(5)
        .onSnapshot(() => {
          // Respond to data
          // ...
        });
    
    // Later ...
    
    // Stop listening to changes
    unsubscribe();
    

    第二种解决方案是使用另一种状态,比如说fetchData,一旦您收到有关负载的数据,将其设置为false,如下所示:-

     const [data, setData] = useState([]);
     const [fetchData, setFetchData] = useState(true);
    
     useEffect(() => {
        if (user) {
          user.getIdTokenResult().then((idTokenResult) => {
            setAdmin(idTokenResult.claims.admin);
          });
    
          db.collection("files")
            .orderBy("timeStamp", "desc")
            .limit(5)
            .onSnapshot((snapshot) => {
              if(fetchData) {
                setData(
                  snapshot.docs.map((doc) => {
                    return [doc.data(), { doc_id: doc.ref.id }];
                  })
                );
                setFetchData(false);
              }
            });
         }
       }, []);
    

    【讨论】:

    • 嘿!感谢你的回答。我尝试了这两种方法,但是它们都不起作用。我认为由于某种原因,状态也在刷新,因此在我删除文档后 fetchData 再次设置为 true。当我在 onSnapshot 方法中记录数据时,它显示一个空数组。想到这里发生了什么,我的大脑很受伤..!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 2020-11-10
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多