Firestore 中的 Flutter 数据保存到 firestore 后显示在 ui

Flutter Data in Firestore gets displayed in the ui after it is saved to firestore

我有一个包含歌曲的列表,将歌曲添加到列表后,它会保存到 Firestore。每次我将一首新歌曲添加到列表并将其保存到 Firestore 时,数据库中的完整列表将再次添加到 UI 中的列表。起初,我认为在开始时调用的我的 Loadall 列表会以某种方式被触发,但经过一些测试后,saveSong 方法导致了这个问题。 这是我的代码

这些是我添加歌曲和从 firebase 加载列表的按钮

我不会包括构建小部件,因为那不重要。

 FloatingActionButton(
          child: const Icon(Icons.add),
          backgroundColor: primaryColor,
          onPressed: () {
            checkSong(Song(
                title: textfieldControllersong.text, like: false, likes: 0));
            reloadlist();
            textfieldControllersong.clear();
            /*addSong(Song(
                title: textfieldControllersong.text, like: false, likes: 0));*/
          },
        ),
        FloatingActionButton(onPressed: () {
          _loadAll();
        })

我有两个 addSongs 方法。一个是从 loadall 方法调用以将这些添加到我的列表中,另一个是来自用户输入

void addSong(Song item) {
    setState(() {
      list.add(item);
    });
    _saveSong(item);
  }

  void addSongfire(Song item) {
    setState(() {
      list.add(item);
    });
  }
void checkSong(Song item) {
    bool isSongFound = false;
    list.forEach((s) {
      if (s.title.trim() == item.title.trim()) {
        setState(() {
          s.likes++;
        });
        isSongFound = true;
      }
    });
    if (!isSongFound) {
      addSong(Song(title: textfieldControllersong.text, like: false, likes: 0));
      /*_saveSong(
          Song(title: textfieldControllersong.text, like: false, likes: 0));*/
    }
  }

这些是保存和加载歌曲的方法我猜错误来自 saveSong 但我不知道为什么在触发 saveSong 后来自 Firesore 的每个数据都会添加到 UI 中的列表再次.

void _saveSong(Song item) async {
    CollectionReference fire = FirebaseFirestore.instance.collection('Songs');
    await fire
        .add({"title": item.title, "like": item.like, "likes": item.likes});
  }

  void _loadAll() {
    Stream<QuerySnapshot> stream = FirebaseFirestore.instance
        .collection('Songs')
        .orderBy("likes")
        .snapshots();
    stream.forEach((QuerySnapshot snap) {
      print("here");
      snap.docs.forEach((DocumentSnapshot doc) {
        addSongFirestore(
            doc.data()['title'], doc.data()['likes'], doc.data()['like']);
      });
    });
  }

void addSongFirestore(String titlef, int likesf, bool likef) {
    addSongfire(Song(title: titlef, like: likef, likes: likesf));
  }

不是在调用 _getAll 时获取一次数据,而是将侦听器附加到该节点。侦听器会在您附加节点时为您提供整个节点,但也会在该节点上的数据更改时调用您的 addSongfire

要解决您的问题,您可以在您的 Widget initState 覆盖中初始化侦听器,或者您只需将 _getAll 更改为仅获取一次数据,如下所示:

Future _loadAll() async {
  QuerySnapshot querySnapshot = await FirebaseFirestore.instance
      .collection('Songs')
      .orderBy("likes")
      .get();

  querySnapshot.docs.forEach((DocumentSnapshot doc) {
    if (doc.exists) {
      addSongFirestore(
          doc.data()['title'], doc.data()['likes'], doc.data()['like']);
    }
  });
}

这只会添加一次数据,并且只会在您使用代码调用它时添加。