【发布时间】:2018-01-22 20:00:12
【问题描述】:
(这是https://github.com/apollographql/apollo-client/issues/1886的后续行动)
我正在尝试构建一个文本输入,它将在用户键入时更新值。
第一次尝试
我首先尝试使用optimisticResponse 在用户键入时更新本地缓存。这是可行的,只是它会在每次击键时触发一个突变。除了用请求淹没网络之外,还存在网络不一致的问题。最后一个突变可能最先到达,第一个突变最后到达。这会导致服务器以陈旧的值结束。下面是这个竞争条件的一个例子:
type: a
mutate request: a
type: b
mutate request: ab
arrives on server: ab
arrives on server: a
现在服务器在graphql中记录了“a”,这是不正确的。
添加去抖动
为了缓解这种情况,我在按键事件中添加了去抖动。尽管这确实有助于解决上述竞争条件,但并不能解决它。如果网络速度低于您的去抖动阈值,仍然可能出现竞争条件。
因为我们现在要对文本输入进行去抖动处理,所以我们需要为该 React 组件引入一个本地状态,以便它在用户输入时立即更新(正如@jbaxleyiii 在 github 问题中所建议的那样)。现在我们的状态存在于两个地方(组件状态和 apollo 缓存)。
这样做的一个大问题是组件在收到新道具时不会更新。例如。当 graphql 更新并推送到客户端时。
添加网络队列
因为去抖动实际上并没有解决竞争条件,所以我添加了一个网络队列(除了去抖动之外),它将管理突变请求以确保只有一个突变一次飞行。如果它在有一个正在运行的突变请求时收到一个突变请求,它将排队等待第一个返回时被触发。如果已经有一个突变排队,它将丢弃它并用新的替换它(一次只能有一个项目在队列中)。这是一个例子:
type: a
send mutate request: a
type: b
queues mutate request: ab << wait to send this until "a" comes back
type: c
replaces queued request: abc << discard the queued request for "ab", it's old now
response from server: a
send mutate request: abc << send the queued mutation and clear the queue
response from server: abc
这保证我们不会有竞争条件(至少来自这个客户......)
但这种方法存在问题。 optimisticResponse 只会在突变消失时更新。如果发生突变,我们需要等待网络返回,然后再应用更新optimisicRespose。在慢速网络上,这个时间可能很长。所以,在上面的例子中,我们不能使用optimisticResponse 来更新到“abc”,直到“send mutate request:abc”。
这不是什么大不了的事,只是延迟,但似乎我们应该能够做到。
尝试在用户输入时更新缓存
在文档中,我了解到我可以使用withApollo 来访问客户端,并在用户通过writeQuery 键入时更新缓存。这取代了对optimisticResponse 的需求。但是,当旧响应返回并从我们下面更新缓存时,现在出现了一个问题。这是一个例子:
action | cache
-------------------------+------------
type: a | a
mutate request: a | a
type: b | ab
queues request: ab | ab
response from server: a | a << oh no!
mutate request: ab | a << we're not using optimisticResponse anymore
... network time ... | a
response from server: ab | ab
我想我们可以使用client.writeQuery 来更新缓存,因为用户键入和optimisticResponse 以在变异请求触发时进行更新,但现在这段代码变得很难理解.
update 函数中也可能有办法处理这个问题,但我还没有走那么远。
帮助?
我对 Apollo 还很陌生,所以也许我遗漏了一些东西。有没有更好的方法来处理阿波罗的许多快速突变?
【问题讨论】:
标签: reactjs graphql apollo react-apollo