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

Should subscribe be working for <Connect>? #3978

Closed
peterlanier opened this issue Sep 5, 2019 · 7 comments
Closed

Should subscribe be working for <Connect>? #3978

peterlanier opened this issue Sep 5, 2019 · 7 comments
Labels
GraphQL Related to GraphQL API issues question General question React React related issues

Comments

@peterlanier
Copy link

peterlanier commented Sep 5, 2019

** Which Category is your question related to? **

React Connect element

** What AWS Services are you utilizing? **

Amplify, Appsync, DynamoDB

** Provide additional details e.g. code snippets **

I've followed the docs pretty closely, but I'm not quite sure why my list of data doesn't update to reflect the latest comment once I click submit. I must manually refresh the page to get the new list. The subscription is firing and the subscription message is showing the prev list plus the newly created object.

What am I missing here? Should I be programmatically refreshing the component somehow? Should I be using the onSubscriptionMsg to push the new object onto the prev? Any help is appreciated.

The code I'm using is VERY close to the docs:

import React, { Component } from "react";
import Amplify from "aws-amplify";
import { graphqlOperation } from "@aws-amplify/api";
import awsconfig from "../../aws-exports";
import { Connect } from "aws-amplify-react";
import { listComments } from "../../graphql/queries";
import { createComment } from "../../graphql/mutations";
import { onCreateComment } from "../../graphql/subscriptions";
import AddComment from "./AddComment";

Amplify.configure(awsconfig);

export default class ListComments extends Component {

  render() {
    const ListView = ({ comments }) => (
      <ul>
        {comments.map(comment => (
          <li key={comment.id}>
            {comment.description}
          </li>
        ))}
      </ul>
    );

    return (
      <div className="comments">
        <Connect
          query={graphqlOperation(listComments, {limit:100})}
          subscription={graphqlOperation(onCreateComment)}
          onSubscriptionMsg={(prev, { onCreateComment }) => {
            console.log("onCreateComment:", onCreateComment);
            console.log("prev:", prev);
            return prev;
          }}
        >
          {({ data: { listComments }, loading, error }) => {
            if (error) return <h3>Error</h3>;
            if (loading || !listComments) return <h3>Loading...</h3>;
            return <ListView comments={listComments.items} />;
          }}
        </Connect>
        <Connect mutation={graphqlOperation(createComment)}>
          {({ mutation }) => <AddComment onCreate={mutation} />}
        </Connect>
      </div>
    );
  }
}

@peterlanier peterlanier changed the title Should subscibe be working? Should subscribe be working for <Connect>? Sep 5, 2019
@haverchuck haverchuck added the React React related issues label Sep 5, 2019
@elorzafe elorzafe added GraphQL Related to GraphQL API issues question General question labels Sep 13, 2019
@visusnet
Copy link

visusnet commented Sep 14, 2019

The Connect component does not update its internal state with the data that it receives from subscriptions because it does not know how. It is possible to subscribe to create, update or delete events. How could Connect know which object should be updated or removed? It can‘t. That‘s what the onSubscriptionMsg callback is for. It receives the old state (prev) and the subscription data. It‘s up to you, to change prev in order to reflect the necessary changes.

This should work for you:

onSubscriptionMsg={(prev, { onCreateComment }) => {
    prev.listComments.items.push(onCreateComment);
    return prev;
}}

Similarly, if you‘d decide to subscribe to update events, you could do something like this:

onSubscriptionMsg={(prev, { onUpdateComment }) => {
   prev.listComments.items =  prev.listComments.items.map(comment => comment.id === onUpdateComment.id ? onUpdateComment : comment);
   return prev;
}}

Using Amplify, you can write a subscription (manually) which subscribes two multiple events. This is actually forbidden by the GraphQL spec (single root field rule) but AppSync doesn‘t care. If you mix multiple types, you can do this:

onSubscriptionMsg={(prev, { onCreateComment, onUpdateComment, onDeleteComment }) => {
    if (onCreateComment) {
        prev.listComments.items.push(onCreateComment);
    } else if (onUpdateComment) {
        prev.listComments.items = prev.listComments.items.map(comment => comment.id === onUpdateComment.id ? onUpdateComment : comment);
    } else if (onDeleteComment) {
        prev.listComments.items = prev.listComments.items.filter(comment => comment.id !== onDeleteComment.id);
    }
    return prev;
}}

@rlimberger
Copy link

@visusnet what does the "subscription" argument look like for multiple events?

@visusnet
Copy link

@rlimberger See the example above for multiple events in onSubscriptionMsg. However, you are asking for the subscription argument of . It is the same as for single subscriptions. The difference is the subscription itself.
The subscription for this example could look like this:

subscription OnCreateOrUpdateOrDeleteComment {
    onCreateComment {
        ...
    }
    onUpdateComment {
        ...
    }
    onDeleteComment {
        ...
    }
}

Please note: This is not allowed by the GraphQL spec. However, AppSync supports it.

@rlimberger
Copy link

rlimberger commented Oct 12, 2019

@visusnet Danke! Got it working. But where/how do I add this custom (multi) subscription? The subscriptions.js file in src/graphql is auto-generated, so can't add it there. I got it working by creating this subscription manually inside App.js like this:

export const onCreateOrUpdateOrDeleteMove = `subscription OnCreateOrUpdateOrDeleteMove {
  onCreateMove {
    id
    from
    to
  }
  onUpdateMove {
    id
    from
    to
  }
  onDeleteMove {
    id
    from
    to
  }
}
`;

Whats the right place for this? Thanks again!

@visusnet
Copy link

@rlimberger There is no right or wrong. Put it where it works for you. You can put it in the graphql folder if you want though. It won‘t be overwritten. Just create a new file, e.g. graphql/customSubscriptions.js and put it there. That‘s what I do. However, you are free to put it wherever you want (except for automatically overwritten files).

@mauerbac
Copy link
Member

Looks like @visusnet helped out here. Thank you! Closing out.

@github-actions
Copy link

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
GraphQL Related to GraphQL API issues question General question React React related issues
Projects
None yet
Development

No branches or pull requests

6 participants