Reputation: 7657
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
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