如何使用Firebase功能实现客户端响应式投票/降票系统

时间:2018-08-12 07:59:24

标签: firebase react-native firebase-realtime-database google-cloud-functions

我正在使用Firebase数据库和云功能来实现upvote downvote系统。

出于响应性的考虑,投票操作还通过react setstate在客户端执行。

vote(id, voteValue){
    let totalVoteObj = this.props.totalVote
    //modify totalVoteObj to change a specific vote value
    //....
    this.setState({
        totalVoteObj: totalVoteObj
    })
}

然后,当云函数增加总投票数时,firebase侦听器将发送newProps

componentWillReceiveProps(nextProps){
    this.setState({
        totalVoteObj: nextProps.totalVote
    })
}

但是,这种方法的问题在于,如果用户在服务器的第一个响应投票按钮闪烁之前很快就获得了2票,那么

Expected                      What user sees on screen
initial                                 0
upvote                                  1
downvote                                0

What happens: 
initial vote state                      0
user upvotes                            1
user downvotes                          0
server responds to first user action    1
server responds to second user action   0

我已经考虑并尝试了几种不同的方法,但是我对任何结果都不完全满意。

  • 比较componentWillReceiveProps的投票,当多个用户对同一个项目进行投票时,它会变得棘手并引起问题。

  • 将用户锁定,直到响应最终使该应用程序的响应速度降低。

  • 尝试了一种云功能解决方案,该解决方案导致了相当大的滞后。

  • setTimeout并在一定时间后评估投票结果并发送单个响应(这也很有意义,因为用户无论如何都不能发出那么多请求,因为这会增加我们的服务器和数据库成本)

一切正常,除非用户向垃圾邮件按钮发送垃圾邮件(即使用户向垃圾邮件发送最终投票值将是正确的),但客户端只会显得笨拙或不稳定。因此,我只是想知道是否有使用React / Redux / Firebase处理此问题的“教科书”解决方案。

编辑:用户拥有唯一的投票,当用户在几秒钟内不断更改其投票时就会发生此问题。与向按钮发送垃圾邮件一样,upvote,downvote,upvote,downvote ...

2 个答案:

答案 0 :(得分:2)

闪烁的特定问题是客户端和服务器更新之间的延迟。您可以通过使用节流/防反弹机制(如rxjs实现)来解决此问题,例如在上次服务器更新之后的X秒后等待,然后发布更新的计数。因此,如果在X秒钟之前又进行了另一个更新,则可以替换它,然后再等待X秒钟再更新视图层。当然,如果有无限数量的更新,则如果视图在Y秒钟内没有更新,则需要保留另一个计数器Y来发布更改,因此无论如何它最终都会更新。

TLDR;如果不实施某种类型的油门/反跳,就无法通过这种架构来停止闪烁。甚至reddit也没有超级实时更新,通常您需要刷新页面以获取更新计数。

componentWillReceiveProps(nextProps){
  if (this.props.totalVote !== nextProps.totalVote) { // check if changed
    totalCountObservable.next(nextProps.totalVote) // publish to observable
  }
}


// Somewhere else, subscribe to observable and throttle updates
totalCountObservable
.throttle(5000)
.subscribe(count => {
  this.setState({
    totalVoteObj: count
  })
})

注意:这是未经测试的伪代码

答案 1 :(得分:1)

您真的需要针对用户快速投票和否决的场景进行优化吗?是谁啊这种情况有多普遍?使UI感到仅响应单个upvote和downvote是有意义的,您已经使用setState完成了。已经移至下一个功能:)