I'm trying to update the cache after a mutation using the updater and optimisticUpdater but it doesn't quite work. Basically, I have a Link type with a votes connection - here's the relevant part of my schema:
type Link implements Node {
createdAt: DateTime!
description: String!
id: ID!
postedBy(filter: UserFilter): User
url: String!
votes(filter: VoteFilter, orderBy: VoteOrderBy, skip: Int, after: String, before: String, first: Int, last: Int): VoteConnection
}
type Vote implements Node {
createdAt: DateTime!
id: ID!
link(filter: LinkFilter): Link!
updatedAt: DateTime!
user(filter: UserFilter): User!
}
# A connection to a list of items.
type VoteConnection {
# Information to aid in pagination.
pageInfo: PageInfo
# A list of edges.
edges: [VoteEdge]
# Count of filtered result set without considering pagination arguments
count: Int!
}
# An edge in a connection.
type VoteEdge {
# The item at the end of the edge.
node: Vote
# A cursor for use in pagination.
cursor: String
}
Here's the code for my Link component where I request the votes in a fragment:
class Link extends Component {
render() {
const userId = localStorage.getItem(GC_USER_ID)
return (
<div>
{userId && <div onClick={() => this._voteForLink()}>â–²</div>}
<div>{this.props.link.description} ({this.props.link.url})</div>
<div>{this.props.link.votes.edges.length} votes | by {this.props.link.postedBy ? this.props.link.postedBy.name : 'Unknown'} {this.props.link.createdAt}</div>
</div>
)
}
_voteForLink = () => {
const userId = localStorage.getItem(GC_USER_ID)
const linkId = this.props.link.id
CreateVoteMutation(userId, linkId, this.props.viewer.id)
}
}
export default createFragmentContainer(Link, graphql`
fragment Link_viewer on Viewer {
id
}
fragment Link_link on Link {
id
description
url
createdAt
postedBy {
id
name
}
votes(last: 1000, orderBy: createdAt_DESC) @connection(key: "Link_votes", filters: []) {
edges {
node {
id
user {
id
}
}
}
}
}
`)
Finally, this is the CreateVoteMutation with the updater:
const mutation = graphql`
mutation CreateVoteMutation($input: CreateVoteInput!) {
createVote(input: $input) {
vote {
id
link {
id
}
user {
id
}
}
}
}
`
export default (userId, linkId, viewerId) => {
const variables = {
input: {
userId,
linkId,
clientMutationId: ""
},
}
commitMutation(
environment,
{
mutation,
variables,
updater: (proxyStore) => {
const createVoteField = proxyStore.getRootField('createVote')
const newVote = createVoteField.getLinkedRecord('vote')
const viewerProxy = proxyStore.get(viewerId)
const connection = ConnectionHandler.getConnection(viewerProxy, 'Link_votes')
// `connection` is undefined, so the `newVote` doesn't get inserted
if (connection) {
ConnectionHandler.insertEdgeAfter(connection, newVote)
}
},
onError: err => console.error(err),
},
)
}
The call to ConnectionHandler.getConnection(viewerProxy, 'Link_votes') only returns undefined, so the newVote doesn't actually get inserted.
Does anyone see what I'm doing wrong?
In the updater function, you could try adding the following code to inspect what data is cached (also under which key)
require('RelayStoreProxyDebugger').dump(proxyStore)
First, When doing mutation with relay modern. After mutation activity ended we can dump our store with RelayStoreProxyDebugger. Its not in docs yet but I know this "trick" 😄 from some comment in another relay issue. It really helpful.
import storeDebugger from 'relay-runtime/lib/RelayStoreProxyDebugger'
//...
commitMutation(
environment,
{
mutation,
variables,
updater: (proxyStore) => {
//...
//...
if (connection) {
ConnectionHandler.insertEdgeAfter(connection, newVote)
}
//dump the store
storeDebugger.dump(proxyStore)
},
//...
},
)
second, since you querying your VoteConnection with last and orderBy arguments, relay connection directive need to know that. so the correct connection directive filters is
votes(last: 1000, orderBy: createdAt_DESC)
@connection(key: "Link_votes", filters: ["last","orderBy"])
third, since your voteconnection argument value is hardcoded one. the connection handler need to know the value of argument. so it can match in the store
const connection = ConnectionHandler.getConnection(viewerProxy, 'Link_votes', {
last: 1000,
orderBy: 'createdAt_DESC'
})
I worked around the issue in a different way.
@nikolasburk how?
@saudpunjwani101 Check the subscriptions chapter of the React & Relay tutorial on How to GraphQL. It's all in there!
Subscription is a good idea but it's way too much work in my case scenario. User just adds an item and I want the list updated. I'm not sure if I require real time updates for that. Any other suggestions before I go that deep?
@nosykretts dumbing the store gives an error,
console.groupCollapsed is not a function
@saudpunjwani101 fixed here https://github.com/facebook/relay/commit/9f682fbc588c391a0b3270ed5e03111b5ac61bf8
hello everyone,
I got same error..
https://github.com/facebook/relay/issues/2163
please give me solution for this.
Most helpful comment
First, When doing mutation with relay modern. After mutation activity ended we can dump our store with
RelayStoreProxyDebugger. Its not in docs yet but I know this "trick" 😄 from some comment in another relay issue. It really helpful.second, since you querying your
VoteConnectionwithlastandorderByarguments, relay connection directive need to know that. so the correct connection directive filters isthird, since your voteconnection argument value is hardcoded one. the connection handler need to know the value of argument. so it can match in the store