Javascript Firebase在添加/删除数据时,应用程序会执行多次功能

Javascript Firebase在添加/删除数据时,应用程序会执行多次功能,javascript,firebase,google-cloud-firestore,Javascript,Firebase,Google Cloud Firestore,我的理财应用程序有问题。当我从我的应用程序(产品集合)中添加/删除数据时,我的应用程序会执行多个函数“sumPrices()”。例如:当我添加一个产品时,生成一次,添加另一个产品,生成两次,添加另一个产品生成三次等。这与删除数据的方式相同 A我的代码中有什么错误吗 Callback.push数据do数组,其中我从firebase取消订阅事件。 AddStatsUI将UI添加到我的DOM index.js: // delete products const handleTableClick

我的理财应用程序有问题。当我从我的应用程序(产品集合)中添加/删除数据时,我的应用程序会执行多个函数“sumPrices()”。例如:当我添加一个产品时,生成一次,添加另一个产品,生成两次,添加另一个产品生成三次等。这与删除数据的方式相同

A我的代码中有什么错误吗

Callback.push数据do数组,其中我从firebase取消订阅事件。 AddStatsUI将UI添加到我的DOM

index.js:

// delete products
    const handleTableClick = e => {
      console.log(e); // mouseevent
      if (e.target.tagName === 'BUTTON'){
          const id = e.target.parentElement.parentElement.getAttribute('data-id');
          db.collection('users')
              .doc(user.uid)
              .collection('products')
              .doc(id)
              .delete()
              .then(() => {
                  // show message
                  updateMssg.innerText = `Product was deleted`;
                  updateMssg.classList.add('act');
                  setTimeout(() => {
                      updateMssg.innerText = '';
                      updateMssg.classList.remove('act');

                  }, 3000);
                  productUI.delete(id);
                  products.sumPrices(user.uid, callbacks).then(value => {
                      sumStats.addStatsUI('','');
                      const unsubscribe = db.collection('users').doc(user.uid).get().then(snapshot => {

                        sumStats.addStatsUI(value[0], snapshot.data().budget);
                      })
                      callbacks.push(unsubscribe);
                  });


          })
      }
    }
    table.addEventListener('click', handleTableClick);
    callbacks.push(() => table.removeEventListener('click', handleTableClick))


    //add new products to firebase
    const handleExpenseFormSubmit = e => {
      e.preventDefault();
      const name = expenseForm.productName.value.trim();
      const price = Number(expenseForm.price.value.trim());

      console.log(`Product added: ${name}, ${price}`);
      const user = firebase.auth().currentUser.uid;
      products.addProduct(name, price, user)
          .then(() => {
              products.sumPrices(user, callbacks).then(value => {
                  sumStats.addStatsUI('','');
                  const unsubscribe = db.collection('users').doc(user).onSnapshot(snapshot => {

                      sumStats.addStatsUI(value, snapshot.data().budget);
                  })
                  callbacks.push(unsubscribe);
              });
              expenseForm.reset()
          })
          .catch(err => console.log(err));

    }
    expenseForm.addEventListener('submit', handleExpenseFormSubmit);
    callbacks.push(() => expenseForm.removeEventListener('submit', handleExpenseFormSubmit))
//get the products and render
const unsubscribe = products.getProducts((data, id) => {

  console.log(data, id);
  productUI.render(data, id);

}, user.uid);
callbacks.push(unsubscribe);

    //update budget + form
const handleBudgetFormSubmit = e => {
  e.preventDefault();
  //update budget
  const budget = Number(budgetForm.budget_value.value.trim());
  sumStats.addStatsUI('', '');
  products.updateBudget(budget, user.uid);
  //reset form
  budgetForm.reset();

  const budgetCart = document.querySelector('#budget');
  budgetCart.classList.remove('active');

  // show message
  updateMssg.innerText = `Your budget was updated to ${budget}$`;
  updateMssg.classList.add('act');

  setTimeout(() => {
    updateMssg.innerText = '';
    updateMssg.classList.remove('act');
  }, 3000);
};
budgetForm.addEventListener('submit', handleBudgetFormSubmit);
callbacks.push(() =>
  budgetForm.removeEventListener('submit', handleBudgetFormSubmit)
);
product.js:

class Product {
constructor(name, price, budget, user) {
    this.products = db.collection('users');
    this.budget = budget;
    this.name = name;
    this.price = price;
    this.user = user;
} 
async addProduct(name, price, user) { //dodaje produkt do firebase
    const now = new Date();
    const product = {
        name: name,
        price: price,
        created_at: firebase.firestore.Timestamp.fromDate(now),
    };
    const response = await this.products.doc(user).collection('products').add(product);
    return response;
}
getProducts(callback, user){ //download list from firebase
    this.products.doc(user).collection('products')
        .orderBy("created_at", "desc")
        .onSnapshot(snapshot => {
            snapshot.docChanges().forEach(change => {
                if(change.type === 'added'){
                    //udpate UI

                    return callback(change.doc.data(), change.doc.id);
                } 
            });


    });
}
updateBudget(budget, user){

    this.budget = budget;
    db.collection('users').doc(user).update({budget: budget});
    // callbacks.push(unsubscribe);
}
async sumPrices(user, callbacks){

    let finish = [];
    const unsubscribe = this.products.doc(user).collection('products').onSnapshot(snapshot => {
        let totalCount = 0;
        snapshot.forEach(doc => {
        totalCount += doc.data().price;
        });

        const a = totalCount;
        console.log(a);
        finish.push(a);
        return finish;
    })
    callbacks.push(unsubscribe);
    return finish;
};
})

sumStatsUI.js:

class Stats {
constructor(stats, circle, budget){
    this.stats = stats;
    this.circle = circle;
    this.budget = budget;
}
addStatsUI(data, budget){
    if(data) {
    const outcome = Math.round(data * 100) / 100;
    const sumAll = Math.round((budget - outcome) * 100) / 100;

    this.stats.innerHTML += `
    <div><span class="budget-name">Budget: </span>  <span class="stat-value">${budget}$</span></div>
    <div><span class="budget-name">Outcome: </span> <span class="stat-value outcome-value">${outcome}$</span></div>
    <div><span class="budget-name">All: </span> <span class="stat-value last-value">${sumAll}$</span></div>
    `;
    const circle = Math.round(((outcome * 100) / budget) * 100) / 100;
    this.circle.innerHTML += `${circle}%`;

    } else {
    this.stats.innerHTML = '';
    this.circle.innerHTML = '';
}};
类统计信息{
构造函数(统计、循环、预算){
this.stats=stats;
这个圆=圆;
这个.预算=预算;
}
addStatsUI(数据、预算){
如果(数据){
常量结果=数学四舍五入(数据*100)/100;
const sumAll=数学四舍五入((预算-结果)*100)/100;
this.stats.innerHTML+=`
预算:${Budget}$
结果:${output}$
全部:${sumAll}$
`;
常数圆=数学圆(((结果*100)/预算)*100)/100;
this.circle.innerHTML+=`${circle}%`;
}否则{
this.stats.innerHTML='';
this.circle.innerHTML='';
}};
})

导出默认统计信息


好的,a对我的代码进行了一些改进,但订阅方面仍然存在问题。现在一切正常,但当我注销并登录函数getProducts()和updateBudget()时,不会取消订阅

代码如下: index.js:

//get the products and render
const unsubscribe = products.getProducts((data, id) => {

  console.log(data, id);
  productUI.render(data, id);

}, user.uid);
callbacks.push(unsubscribe);

    //update budget + form
const handleBudgetFormSubmit = e => {
  e.preventDefault();
  //update budget
  const budget = Number(budgetForm.budget_value.value.trim());
  sumStats.addStatsUI('', '');
  products.updateBudget(budget, user.uid);
  //reset form
  budgetForm.reset();

  const budgetCart = document.querySelector('#budget');
  budgetCart.classList.remove('active');

  // show message
  updateMssg.innerText = `Your budget was updated to ${budget}$`;
  updateMssg.classList.add('act');

  setTimeout(() => {
    updateMssg.innerText = '';
    updateMssg.classList.remove('act');
  }, 3000);
};
budgetForm.addEventListener('submit', handleBudgetFormSubmit);
callbacks.push(() =>
  budgetForm.removeEventListener('submit', handleBudgetFormSubmit)
);
如果(用户):

} });

getProducts()和updateBudget():

}

当我注销并登录时:

当我有了getProducts并将product添加到集合中时,此函数将渲染(render())product两次,但将其添加到集合中一次。当我更新预算时,返回该预算,但之后返回0(在DOM上,ShowBudget a可以看到“Infinity”)

还有一件事,当我注销时,控制台返回错误:

TypeError: callback is not a function
    at eval (index.js:182)
    at Array.forEach (<anonymous>)
    at Object.eval [as next] (index.js:182)
    at eval (index.cjs.js:1226)
    at eval (index.cjs.js:1336)
TypeError:回调不是函数
评估时(索引js:182)
在Array.forEach()处
在Object.eval[as next](index.js:182)
评估时(索引:1226)
评估时(索引:1336)
我认为这是因为getProducts和updateBudget不返回unsubscribe,而是未定义


也许有人能解决这个问题?

好的,对我的代码进行一些改进,但订阅方面仍然存在问题。现在一切正常,但当我注销并登录函数getProducts()和updateBudget()时,不会取消订阅

代码如下: index.js:

//get the products and render
const unsubscribe = products.getProducts((data, id) => {

  console.log(data, id);
  productUI.render(data, id);

}, user.uid);
callbacks.push(unsubscribe);

    //update budget + form
const handleBudgetFormSubmit = e => {
  e.preventDefault();
  //update budget
  const budget = Number(budgetForm.budget_value.value.trim());
  sumStats.addStatsUI('', '');
  products.updateBudget(budget, user.uid);
  //reset form
  budgetForm.reset();

  const budgetCart = document.querySelector('#budget');
  budgetCart.classList.remove('active');

  // show message
  updateMssg.innerText = `Your budget was updated to ${budget}$`;
  updateMssg.classList.add('act');

  setTimeout(() => {
    updateMssg.innerText = '';
    updateMssg.classList.remove('act');
  }, 3000);
};
budgetForm.addEventListener('submit', handleBudgetFormSubmit);
callbacks.push(() =>
  budgetForm.removeEventListener('submit', handleBudgetFormSubmit)
);
如果(用户):

} });

getProducts()和updateBudget():

}

当我注销并登录时:

当我有了getProducts并将product添加到集合中时,此函数将渲染(render())product两次,但将其添加到集合中一次。当我更新预算时,返回该预算,但之后返回0(在DOM上,ShowBudget a可以看到“Infinity”)

还有一件事,当我注销时,控制台返回错误:

TypeError: callback is not a function
    at eval (index.js:182)
    at Array.forEach (<anonymous>)
    at Object.eval [as next] (index.js:182)
    at eval (index.cjs.js:1226)
    at eval (index.cjs.js:1336)
TypeError:回调不是函数
评估时(索引js:182)
在Array.forEach()处
在Object.eval[as next](index.js:182)
评估时(索引:1226)
评估时(索引:1336)
我认为这是因为getProducts和updateBudget不返回unsubscribe,而是未定义


也许有人能解决这个问题?

大家好,欢迎光临!我无法理解到底是什么问题。从代码来看,似乎每次添加产品时都会调用sumPrices。另一方面,这似乎也是一个问题。。。它应该如何工作比…?每次当我添加或删除数据表与费用(看屏幕截图)这使sumPrices()但应用程序做代码sumPrices()这样:当我添加一个产品,使一次,添加另一个产品,使两次,添加另一个产品使三等。这发生在相同的方式删除数据。当这种情况发生时,回报率将上升。第一次:返回结果一次,下一次返回两次等。如果这还不够,我可以制作视频,它是如何工作的。你有一个订阅,你没有取消订阅,例如每次你调用
getProducts
它都会创建一个新订阅,我必须在其中放置“取消订阅”来修复它?在函数或index.js中获取产品@Reza@mGryska两种方法:您可以调用getProducts一次,该函数需要返回observable,您订阅它,然后当您的组件正在销毁时,您需要取消订阅,另一种方法是在管道中使用
first()
,它将结束订阅,并且每次您都可以调用getProductsHi并欢迎!我无法理解到底是什么问题。从代码来看,似乎每次添加产品时都会调用sumPrices。另一方面,这似乎也是一个问题。。。它应该如何工作比…?每次当我添加或删除数据表与费用(看屏幕截图)这使sumPrices()但应用程序做代码sumPrices()这样:当我添加一个产品,使一次,添加另一个产品,使两次,添加另一个产品使三等。这发生在相同的方式删除数据。当这种情况发生时,回报率将上升。第一次:返回结果一次,下一次返回两次等。如果这还不够,我可以制作视频,它是如何工作的。你有一个订阅,你没有取消订阅,例如每次你调用
getProducts
它都会创建一个新订阅,我必须在其中放置“取消订阅”来修复它?在函数或index.js中获取产品@Reza@mGryska两种方法:您可以调用getProducts一次,该函数需要返回observable,您订阅了它,然后当您的组件正在销毁时,您需要取消订阅,另一种方法是在管道中使用
first()
,它将结束订阅,并且每次您都可以调用getProducts