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
相关产品推荐
相关产品推荐

