使用订阅的乐观UI是否有意义?
基本上是这样的:
addChannelMutation({
variables: { name: eventValue },
optimisticResponse: {
__typename: "Mutation",
addChannel: {
__typename: "Channel",
id: data.channels.length,
name: eventValue
}
},
update: (store, { data: { addChannel } }) => {
// Read the data from our cache for this query.
const data = store.readQuery({ query: channelsListQuery });
// Add our comment from the mutation to the end.
data.channels.push(addChannel);
// Write our data back to the cache.
store.writeQuery({ query: channelsListQuery, data });
}
}).then(res => {});
它会添加两次相同的项目,触发重复的键异常。 因此,乐观的ui对订阅有意义吗?
答案 0 :(得分:4)
optimisticResponse
会触发update
。然后,当服务器响应时,再次触发update
并用响应替换乐观占位符。
订阅只会在服务器突变解决后才会发出,所以基本上在服务器响应时。
如果您没有包含Optimistic UI并且您有任何类型的延迟,则在服务器发送响应之前,结果将不会显示。这可能是一个问题,例如在聊天应用中,如果用户在单击发送按钮后没有看到他们的消息。他们会一直点击按钮并多次发送消息:/
在使用Optimisic UI和Subscriptions时,要对抗欺骗,有两种策略包括:
检查客户端上的欺骗行为:
在update
和updateQuery
函数中:
// super simplified dupe doc checker
function isDuplicateDocument(newDocument, existingDocuments) {
return newDocument.id !== null && existingDocuments.some(doc => newDocument.id === doc.id);
}
addChannelMutation({
variables: { name: eventValue },
optimisticResponse: {
__typename: "Mutation",
addChannel: {
__typename: "Channel",
id: data.channels.length,
name: eventValue
}
},
update: (store, { data: { addChannel } }) => {
// Read the data from our cache for this query.
const data = store.readQuery({ query: channelsListQuery });
if (isDuplicateDocument(addChannel, data.channels) {
return;
}
// Add our comment from the mutation to the end.
data.channels.push(addChannel);
// Write our data back to the cache.
store.writeQuery({ query: channelsListQuery, data });
}
}).then(res => {});
还在订阅中的updateQuery
内:
subscribeToMore({
...
updateQuery: (previousResult, { subscriptionData }) => {
const newChannel = subscriptionData.data.addChannel;
// if it's our own mutation
// we might get the subscription result
// after the mutation result.
if (isDuplicateDocument(
newChannel, previousResult.channels)
) {
return previousResult;
}
return update(previousResult, {
channels: {
$push: [newChannel],
},
});
},
或者您可以将服务器上的订阅限制为不向新频道的创建者发送。