Firebase child_added 仅适用于新项目
Posted
技术标签:
【中文标题】Firebase child_added 仅适用于新项目【英文标题】:Firebase child_added for new items only 【发布时间】:2017-09-12 10:43:59 【问题描述】:我将 Firebase 和 Node 与 Redux 一起使用。我正在从一个键加载所有对象,如下所示。
firebaseDb.child('invites').on('child_added', snapshot =>
)
这种方法背后的想法是,我们从数据库中获取有效负载,并且只使用一个操作通过 Reducer 更新我的本地数据存储。
接下来,我需要监听密钥邀请的任何 NEW 或 UPDATED 子级。 然而,现在的问题是 child_added 事件会触发所有现有键以及新添加的键。我不想要这种行为,我只需要新密钥,因为我已经检索了现有数据。
我知道 child_added 通常用于这种类型的操作,但是,我希望减少触发的操作数量,并因此触发渲染。
实现这一目标的最佳模式是什么?
谢谢,
【问题讨论】:
只有当监听器第一次触发时,child_added 才会触发该节点子节点的数量,之后才会在添加新子节点时触发。 我知道,这就是我在问题中提到的......我只想要新项目...... 【参考方案1】:虽然limit方法相当不错并且效率很高,但是你仍然需要在child_added
中添加一个检查,最后一个要抓取的项目。另外我不知道是否仍然如此,但是您可能会从以前删除的项目中获得“旧”事件,因此您可能也需要注意这一点。
其他解决方案是:
使用布尔值防止旧添加的对象调用回调
let newItems = false
firebaseDb.child('invites').on('child_added', snapshot =>
if (!newItems) return
// do
)
firebaseDb.child('invites').once('value', () =>
newItems = true
)
这种方法的缺点是它意味着如果你有一个很大的初始列表,它可能会导致什么都不做的事件可能会出现问题。
或者,如果您的邀请上有时间戳,请执行以下操作
firebaseDb.child('invites')
.orderByChild('timestamp')
.startAt(Date.now())
.on('child_added', snapshot =>
// do
)
【讨论】:
在使用时间戳时不要忘记考虑服务器和客户端之间的时间差。查看文档中的Clock skew。检索到 serverTimeOffset 后,可以轻松添加它,例如.startAt(Date.now() + serverTimeOffset)
。【参考方案2】:
我已经使用以下方法解决了这个问题。
firebaseDb.child('invites').limitToLast(1).on('child_added', cb)
firebaseDb.child('invites').on('child_changed', cb)
limitToLast(1) 获取邀请的最后一个子对象,然后侦听任何新的子对象,将快照对象传递给 cb 回调。
child_changed 监听任何对邀请的子更新,将快照传递给 cb
【讨论】:
limitToLast(1) 承诺最后添加的项目正常。但是如果在您授权之前添加了超过 1 条记录会发生什么。除了最后一个,它会丢失它们。我认为错误的答案。对吗? 这对我不起作用。添加的孩子不会触发任何事件。【参考方案3】:我通过忽略child_added
并仅使用child_changed
解决了这个问题。我这样做的方法是对我需要处理的任何项目执行update()
,在将它们推送到数据库之后。此解决方案将取决于您的需求,但一个示例是在您希望触发事件时更新时间戳键。例如:
var newObj = ...
// push the new item with no events
fb.push(newObj)
// update a timestamp key on the item to trigger child_changed
fb.update( updated: yourTimeStamp )
【讨论】:
【参考方案4】:还有另一种解决方案: 获取孩子的数量并提取该值: 它正在工作。
var ref = firebaseDb.child('invites')
ref.once('value').then((dataSnapshot) =>
return dataSnapshot.numChildren()
).then((count) =>
ref .on('child_added', (child) =>
if(count>0)
count--
return
console.log("child really added")
);
);
【讨论】:
【参考方案5】:如果您的文档键是基于时间的(unix epoch、ISO8601 或 firebase 'push' 键),这种方法类似于 @balthazar 提出的第二种方法,对我们来说效果很好:
const maxDataPoints = 100;
const ref = firebase.database().ref("someKey").orderByKey();
// load the initial data, up to whatever max rows we want
const initialData = await ref.limitToLast(maxDataPoints).once("value")
// get the last key of the data we retrieved
const lastDataPoint = initialDataTimebasedKeys.length > 0 ? initialDataTimebasedKeys[initialDataTimebasedKeys.length - 1].toString() : "0"
// start listening for additions past this point...
// this works because we're fetching ordered by key
// and the key is timebased
const subscriptionRef = ref.startAt(lastDataPoint + "0");
const listener = subscriptionRef.on("child_added", async (snapshot) =>
// do something here
);
【讨论】:
以上是关于Firebase child_added 仅适用于新项目的主要内容,如果未能解决你的问题,请参考以下文章
firebase 社交登录不适用于我的 android 设备,仅适用于网络
如何将 Firebase 数据检索到 TableView android 中?我应该使用 RecycleView 还是仅适用于列表?