我正在使用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 ...
答案 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完成了。已经移至下一个功能:)