Skip to content

Instantly share code, notes, and snippets.

@ephys
Created June 18, 2020 14:13
Show Gist options
  • Save ephys/5871cc905c03781bfa6356558ccaedba to your computer and use it in GitHub Desktop.
Save ephys/5871cc905c03781bfa6356558ccaedba to your computer and use it in GitHub Desktop.
import { optimisticUpdate, update } from './swr-util';
// FIXME: live updates are not optimistically updated by this as they are not handled by SWR
export async function sendMessageMutation(viewer: UserIdentifier, to: UserIdentifier, message: string, temporaryId = `optimistic:${Date.now()}${Math.random()}`) {
const rollback = optimisticUpdate(cache => {
const optimisticMessage = {
id: temporaryId,
body: message,
fromUserId: viewer,
read: null,
sentAt: (new Date()).toISOString(),
optimistic: true,
};
sendMessageUpdater(optimisticMessage, to, cache);
});
let persistedMessage;
try {
// API call
persistedMessage = await sendMessage(to, message);
} finally {
// rollback optimistic version no matter what, if message fails this will throw and
// persistedMessage won't be added
rollback();
}
// update with real value
update(cache => {
sendMessageUpdater(persistedMessage, to, cache);
});
return persistedMessage;
}
function sendMessageUpdater(newMessage, contactId, cache) {
const firstPageCacheKey = getMessagesKey(contactId);
const conversationsKey = getConversationsKey(false);
const messages = cache.getData(firstPageCacheKey);
cache.mutate(
firstPageCacheKey,
{
...messages,
nodes: [
newMessage,
...messages.nodes,
],
},
false,
);
const conversations = cache.getData(conversationsKey);
if (conversations) {
cache.mutate(conversationsKey, {
...conversations,
nodes: conversations.nodes.map(conversation => {
if (conversation.contact.id !== contactId) {
return conversation;
}
return {
...conversation,
message: newMessage,
};
}),
}, false);
}
}
function getSwrKey(key: string | string[]) {
if (Array.isArray(key)) {
return hashSwrKey(key);
}
return key;
}
function getSwrData(key: string | string[]) {
return cache.get(getSwrKey(key));
}
export function optimisticUpdate(callback) {
const oldData = {};
function cancellableMutate(key, value) {
const transformedKey = getSwrKey(key);
oldData[transformedKey] = oldData[transformedKey] || { key, value: getSwrData(key) };
mutate(key, value, false);
}
callback({ mutate: cancellableMutate, getData: getSwrData });
return function rollback() {
for (const { key, value } of Object.values(oldData)) {
mutate(key, value, false);
}
};
}
export function update(callback) {
callback({ mutate, getData: getSwrData });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment