Does it make sense having Optimistic UI with subscriptions?
So basically:
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 => {});
It adds twice the same item triggering a duplicate key exception. Thus does optimistic ui make sense with subscriptions?
optimisticResponse
triggers update
before a response is received by the server. Then when the server responds, update
is triggered again and replaces the optimistic placeholder with the response.
Subscriptions will emit only once the server mutation resolves, so essentially when the server is responding.
If you didn't include Optimistic UI and you had any sort of latency, the result won't show up until the server sends a response. This can be an issue, for example in a chat app, if the user doesn't see their message as soon as they click the send button. They'll keep clicking the button and send the message multiple times :/
To fight dupes when using Optimisic UI and Subscriptions, two strategies include:
check for dupes on the client:
in the update
and updateQuery
functions:
// 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 => {});
And also inside updateQuery
in your subscription:
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],
},
});
},
Or you can limit your subscription on the server to not emit to the creator of the new channel.