Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What is the appropriate way to handle multiple subscriptions/mutations that update the same data? #3457

Closed
Nickersoft opened this issue May 15, 2018 · 1 comment

Comments

@Nickersoft
Copy link

Filing this here as it is not only a generic question, but because it may hint to bugs or lack of functionality in the Apollo Client. Hopefully I can keep it somewhat short.

I'm currently using Apollo subscriptions and mutations to manage a chat application. There are two primary ways the cache gets manually updated, one via a subscription and the other a mutation. The mutation creates a new text message on the server and looks like this:

    mutation NewTextMessage($input: TextMessageInput!) {
        createTextMessage(input: $input) {
            id
            content
            authorID
            created
            unread
        }
    }

while the other is a subscription that subscribes to any new message sent to a user's conversation:

    subscription onMessageSent($conversationID: ID!) {
        messageSent(conversationID: $conversationID) {
            id
            content
            authorID
            conversationID
            created
            unread
        }
    }

There are two screens in my app. One is a list of conversations, which subscribes to messageSent so it can update message previews in the ListItem for the respective conversation, and the other is an actual conversation, that also subscribes to messageSent to update its list of messages. However, seeing both the mutation and subscription need to update the cache, often times I need to utilize helper functions in order to successfully merge objects and prevent duplicates from appearing. For example, to update the conversation ListItem after a new message comes in:

updateQuery: (prev, { subscriptionData }) => {
    if (!subscriptionData.data) return prev;

    const { messageSent: newMessage } = subscriptionData.data;
    const { conversations } = prev;

    // Locate the actual conversation first
    const msgIndex = conversations.findIndex(x => x.id === params.conversationID);
   
    // If we found it
    if (msgIndex >= 0) {
        // Create a new conversation object from the old one
        const convo = conversations[msgIndex];
        const newConvo = {
            ...convo,
            messages: _.unionBy([newMessage], convo.messages, 'id')
        };

        // Merge it into the props
        return {
            ...prev,
            conversations: _.unionBy([newConvo], conversations, 'id')
        };
    }

    return prev;
}

Likewise, to prevent duplicates within actual conversations:

updateQuery: (
    prev,
    {
        subscriptionData: {
            data: { messageSent }
        }
    }
) => {
    const { conversation } = prev;
    const { messages } = conversation;

    if (!messageSent) return prev;

    return {
        ...prev,
        conversation: {
            ...conversation,
            // Use unionBy() to prevent messages with duplicate IDs
            messages: _.unionBy([messageSent], messages, 'id')
        }
    };
}

You'll notice these implementations use functions such as unionBy and findIndex, which I feel is rather convoluted and unnecessary. That said, without them, you send a message, it gets stored in the cache, the app receives the subscription push for that message, adds it to the cache, while the conversation list does that same, often resulting in 3-4 copies of the same message in the cache! So every time you send a message it appears 4 times or so. I know Apollo is supposed to merge cache entries by id, and each query I'm using has an id. Is this missing functionality in the Apollo client or am I missing something that will make my life easier?

@hwillson
Copy link
Member

hwillson commented Jul 9, 2019

Issues here are reserved for Apollo Client bugs. You'll have a much better chance of getting this answered in Apollo's Spectrum community or on Stack Overflow. Thanks!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants