Firestore onSnapshot更新并向DOM添加数组,而不是仅更新

时间:2019-05-27 03:45:26

标签: reactjs firebase google-cloud-firestore

我有来自Firestore的数据,我正在将这些数据映射到DOM,然后更新客户端。在数据更新所需的方式时,每次事件触发时,都会向DOM中添加另一个更新的数组。

我认为问题在于点击事件的设置方式,但是我不确定如何将我的客户端操作应用于数组。

这是我的设置和点击事件

function App() {
  const [heroesArr, setHeroesArr] = useState([]);
  const db = firebase.firestore();
  const onFetch = () => {
    const newHeroes = [];
    db.collection("characterOptions").onSnapshot(coll => {
      coll.forEach(doc => {
        const { Name, uidDownvoted, uidUpvoted, votes } = doc.data();
        newHeroes.push({
          key: doc.id,
          doc,
          Name,
          uidDownvoted,
          uidUpvoted,
          votes
        });
      });
      setHeroesArr(newHeroes);
    });
  };

  const onUpVote = i => {
    const collRef = db.collection("characterOptions");
    setHeroesArr(heroesArr =>
      heroesArr.map((item, o) => {
        if (i === o && !item.uidDownvoted && !item.uidUpvoted) {
          collRef.doc(item.key).update({
            votes: firebase.firestore.FieldValue.increment(1),
            uidUpvoted: true
          });
        } else if (i === o && !item.uidDownvoted && item.uidUpvoted) {
          collRef.doc(item.key).update({
            votes: firebase.firestore.FieldValue.increment(-1),
            uidUpvoted: false
          });
        } else if (i === o && item.uidDownvoted && !item.uidUpvoted) {
          collRef.doc(item.key).update({
            votes: firebase.firestore.FieldValue.increment(2),
            uidUpvoted: true,
            uidDownvoted: false
          });
        }
        return item;
      })
    );
  };

这是标记

 return (
    <div className="App">
      <button onClick={onFetch}>click</button>
      {heroesArr.map((item, i) => (
        <div key={item.key}>
          <p>{item.Name}</p>
          <p>{item.votes}</p>
          {item.uidDownvoted && <p>this has been downvoted</p>}
          {item.uidUpvoted && <p>this has been upvoted</p>}
          <button onClick={() => onUpVote(i)}>Upvote</button>
        </div>
      ))}
    </div>
  );

显然,我只是希望数组能够更新,而不是每次触发click事件时都创建一个附加的更新副本。

1 个答案:

答案 0 :(得分:0)

您有两个选择:

  1. 始终清除数组
  2. 执行增量更新

由于第一个选项最简单,因此我将向您显示代码。

现在,即使您仅在newHeroes内使用它,也要声明onSnapshot。这意味着每次循环coll.forEach()时,您都将所有元素添加到newHeroes中,包括您以前阅读过的元素。

最简单的选择是在回调内部声明newHeroes,以便每次运行回调时都将其清空。

db.collection("characterOptions").onSnapshot(coll => {
  const newHeroes = [];
  coll.forEach(doc => {
    const { Name, uidDownvoted, uidUpvoted, votes } = doc.data();
    newHeroes.push({
      key: doc.id,
      doc,
      Name,
      uidDownvoted,
      uidUpvoted,
      votes
    });
  });
  setHeroesArr(newHeroes);
});

一种替代方法是使用Firestore提供的有关哪些文档是新文档,哪些文档已更新等信息。要获取此信息,您需要遍历coll.documentChanges。有关此示例,请参见view changes between snapshots上的文档。