You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo+Firebase开发问题:添加数据库子节点后立即被移除

问题分析与解决方案

你的问题核心在于使用了**on('child_added')持续监听数据变化**,而不是一次性查询。当你第一次执行删除操作时,这个监听并没有被移除,所以当你再次添加同一个userTalk时,child_added事件会被触发,找到刚添加的那条记录并执行删除,就出现了“先添加后立即移除”的现象。

具体问题点拆解

on('child_added')会在当前匹配的所有子节点上触发一次,并且之后每当有新的匹配节点添加时都会再次触发。你第一次删除时设置的这个监听一直存在,所以第二次添加userTalk时,这个监听会立刻检测到新添加的节点,然后执行snap.ref.remove(),导致刚添加的数据被瞬间删掉。

修复方案

1. 改用一次性查询once('value')

我们只需要在点击时查询一次当前用户的userTalk记录,不需要持续监听,所以用once('value')替代on('child_added'),查询完成后就不会再触发后续事件。

2. 优化查询后的遍历逻辑

orderByChild+equalTo返回的是一个快照集合,需要遍历所有子节点找到匹配的talk记录,而不是只处理第一个child_added事件(避免漏删或误删)。

3. 可选:优化数据结构提升性能

如果把userTalks的节点设计为${loggedUser.uid}_${talk.id}作为key,就可以直接通过key定位到记录,无需查询,效率更高。比如:

// 添加时直接用组合key
firebaseApp.database().ref(`userTalks/${loggedUser.uid}_${talk.id}`).set({
  user: loggedUser.uid,
  talk: talk.id
})

// 删除时直接删除对应key的节点
firebaseApp.database().ref(`userTalks/${loggedUser.uid}_${talk.id}`).remove()

修改后的完整代码

addOrRemoveUserTalk(loggedUser, talk) {
  if(this.state.buttonText === 'Dislike') {
    // 改用once一次性查询,避免持续监听
    firebaseApp.database().ref().child('userTalks')
      .orderByChild('user')
      .equalTo(loggedUser.uid)
      .once('value', (snapshot) => {
        snapshot.forEach((snap) => {
          const userTalk = snap.val();
          if(userTalk.talk === talk.id) {
            console.log("CHILD WILL BE DESTROYED");
            snap.ref.remove();
            this.setState({ buttonText: 'Like' });
          }
        });
      });
  } else {
    console.log("CHILD WILL BE ADDED");
    firebaseApp.database().ref().child('userTalks').push({
      user: loggedUser.uid,
      talk: talk.id,
    });
    this.setState({ buttonText: 'Dislike' });
  }
}

额外说明

  • 把setState移到异步操作的回调里,确保状态更新和数据库操作同步完成,避免UI状态和实际数据不一致。
  • 用===替代==做严格相等判断,减少潜在的类型匹配问题。

内容的提问来源于stack exchange,提问作者Alex Lecco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:56:18