让我们以聊天应用程序为例。用户可以访问多个聊天线程,每个线程都有多条消息。用户界面由左侧的线程列表 ( listThreads
) 组成,其中包含对方的姓名、最后一条消息、未读消息计数和最后一条消息的日期和时间,以及实际消息 ( viewThread
) 和右侧的回复框(想想 facebook messenger)。
当用户选择一个消息线程时,viewThread
组件订阅一个查询,如下所示:
query thread {
threads(id: 'xxxx') {
id
other_party { id name }
unread_messages
messages {
sent_by { id }
timestamp
text
}
}
为了进行实时更新,它q.subscriptToMore
通过以下方式订阅:
subcription newMessages {
newMessage(thread_id: 'xxx') {
sent_by { id }
timestamp
text
}
}
这完美地工作,新消息按应有的方式显示。
为了列出可用的消息线程,查询所有线程的不太详细的视图:
query listThreads {
threads {
id
other_party { id name }
unread_messages
last_updated_at
}
}
为了使列表保持同步,使用相同的订阅,而不过滤thread_id
,并且手动更新线程列表数据
这也很好用。
但是,如果选择了一个线程,则会缓存该线程A
的消息。A
如果B
之后选择线程,则获取线程详细信息的查询的订阅将A
被销毁,因为当路由器退出viewThread
组件时,可观察对象被销毁。
A
如果在用户查看线程时消息到达线程B
,threadList
则更新(因为该订阅是实时的),但如果用户切换回线程A
,则从缓存中加载消息,这些消息现在已过时,因为没有订阅将更新或使缓存无效的特定消息线程。
在用户导航到完全不同的页面的其他情况下,线程列表不会出现在视图中,问题更加明显,因为没有任何与积极订阅的聊天消息相关的内容,因此没有任何内容可以使缓存数据无效当有新消息到达时,尽管服务器理论上提供了一种通过提供新消息订阅事件来做到这一点的方法。
我的问题如下:
保持 Apollo 缓存的数据同步/无效的最佳实践是什么,这些数据并未积极“使用”?保持嵌套数据同步的最佳实践是什么(事件线程的消息 [见下文])。我觉得不必在事件查询中实现有关如何订阅和更新消息数据的逻辑是一个干净的解决方案。
使用.subscribeToMore
可以使积极使用的数据保持同步,但是一旦不再使用该查询,数据就会保留在缓存中,这些数据可能会随着时间的推移而过时,也可能不会过时。当可观察对象超出范围时,有没有办法删除缓存的数据?只要至少有一个查询使用它,就保持这些数据缓存,因为我相信它还实现了基于服务器推送事件保持同步的逻辑。
是否应该使用订阅(通过 SPA 的整个生命周期)所有订阅事件并包含有关如何更新每种类型的缓存数据(如果存在于缓存中)的知识的服务?(可以通知该服务哪些数据需要保持同步以避免使用不必要的资源)(如在订阅所有newMessage
事件并基于此戳缓存的服务中)?这会自动为返回的对象引用此类数据的查询发出新值吗?(更新是否message:1
会使在其消息字段中返回相同的线程查询message:1
自动发出一个新值)或者这些查询也必须手动更新?
这在扩展这个模型时开始变得非常麻烦,说Events
也有自己的聊天线程,所以event { thread { messages { ... } }
现在查询需要订阅newMessage
订阅,这打破了封装和单一责任原则。订阅newMessage
数据需要提供与事件关联的消息线程的 id 也是有问题的,但在查询返回之前这是不知道的。由于这个.subscribeToMore
不能使用,因为那时我还没有thread_id
可用的。