首页 > 解决方案 > Firestore onSnapshot 更新并将数组添加到 DOM 而不是仅更新

问题描述

我有来自 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>
  );

我显然只是希望数组更新,而不是每次触发点击事件时创建一个额外的更新副本。

标签: reactjsfirebasegoogle-cloud-firestore

解决方案


你有两个选择:

  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. 有关这方面的示例,请参阅有关快照之间视图更改的文档。


推荐阅读