Martin Dawson
Martin Dawson

Reputation: 7657

Relay Subscriptions correct way to use?

At the moment I have to loop through the existing records in the connection to check if the record already exists and only if it doesn't then I add the new edge to it. The reason I need to do this is that when the page is loaded the comments get retrieved by CommentsContainer but the subscription also gets all the comments which results in every comment being duplicated.

App.js:

const AppContainer = compose(
  lifecycle({
    componentDidMount() {
      commentSubscription();
    },
  }),
)(App);

My subscription:

import { requestSubscription, graphql } from 'react-relay';
import { ConnectionHandler } from 'relay-runtime';

import environment from '../app/environment/environment';

const subscription = graphql`
  subscription commentSubscription {
    commentAdded {
      id
      ...commentContainer_comment
      audio {
        id
      }
    }
  }
`;

export default () => requestSubscription(
  environment,
  {
    subscription,
    onError: error => console.error(error), // eslint-disable-line no-console
    updater: (store) => {
      const commentAdded = store.getRootField('commentAdded');
      const audioRecord = commentAdded.getLinkedRecord('audio');
      const audioId = audioRecord.getValue('id');
      const audioProxy = store.get(audioId);
      const connection = ConnectionHandler.getConnection(
        audioProxy,
        'commentsContainer_comments',
      );

      if (connection) {
        const existingRecords = connection.getLinkedRecords('edges');
        const recordAlreadyExists = existingRecords.some((existingRecord) => {
          const node = existingRecord.getLinkedRecord('node');
          const existingId = node.getValue('id');
          const commentId = commentAdded.getValue('id');

          return existingId === commentId;
        });

        if (!recordAlreadyExists) {
          const edge = ConnectionHandler.createEdge(store, connection, commentAdded, 'CommentPayloadEdge');

          ConnectionHandler.insertEdgeBefore(connection, edge);
        }
      }
    },
  },
);

CommentsContainer:

import { compose } from 'recompose';
import { graphql } from 'react-relay';
import { fragmentContainer } from 'recompose-relay-modern';

import Comments from './comments';

const fragments = graphql`
  fragment commentsContainer_audio on Audio {
    id
    ...commentBoxContainer_audio
    comments(
      first: $count
      after: $cursor
    ) @connection(key: "commentsContainer_comments") {
      edges {
        node {
          commentId
          ...commentContainer_comment
        }
      }
    }
  }
`;

export default compose(
  fragmentContainer(fragments),
)(Comments);

CommentContainer:

import { compose } from 'recompose';
import { fragmentContainer } from 'recompose-relay-modern';
import { graphql } from 'react-relay';

import Comment from './comment';

const fragments = graphql`
  fragment commentContainer_comment on Comment {
    id
    body
    dateAdded
    user {
      userName
    }
  }
`;

export default compose(
  fragmentContainer(fragments),
)(Comment);

Is this the correct way to use Relay subscriptions? It seems inefficient having to loop through every comment to check if it already exists.

Upvotes: 1

Views: 989

Answers (1)

Cristian Irimiea
Cristian Irimiea

Reputation: 111

I cannot add comment i am under 50rep. I am struggling with subscriptions right now. I can tell you that loop is not the right way "DataID (type): A globally unique or client-generated identifier for a record, stored as a string." , this is form Relay Modern docs. Relay is checking automatically an also throws error in console if finds a duplicate id. In my subscriptions i use 3 mutation types: CREATED, UPDATED, DELETED. So for each mutation type i use a switch:

updater: (store) => {
      const getRootField = store.getRootField('UserSubscription');
      const mutation = getRootField.getValue('mutation');
      const node = getRootField.getLinkedRecord('node');
      switch (mutation) {
        case 'CREATED': {
          const clientProxy = store.get('client:root:viewer:allUsers');
          const newEdge = ConnectionHandler.createEdge(
            store,
            clientProxy,
            node,
            'UserEdge',
          );
          ConnectionHandler.insertEdgeBefore(clientProxy, newEdge);
        }
          break;
        case 'UPDATED':
          console.log('Updated');
          break;
        case 'DELETED': {
          const nodeId = node.getDataID();
          console.log(nodeId);
          store.delete(nodeId);
        }
          break;
        default:
          console.log('Something is wrong');
      }

Upvotes: 2

Related Questions