Hi folks, yesterday I noticed a strange behavior in my project: somehow my removal mutations stopped working. I couldn't identify the reason of this, neither did any changes in this part of the project.
Here's my mutation:
import { commitMutation, graphql } from 'react-relay'
import { ConnectionHandler } from 'relay-runtime'
const mutation = graphql`
mutation UserRemoveMutation($input: UserRemoveInput!) {
UserRemove(input: $input) {
deletedID
error
}
}
`
function sharedUpdater (store, viewer, deletedID) {
const viewerProxy = store.get(viewer.id)
const conn = ConnectionHandler.getConnection(
viewerProxy,
'list_users'
)
ConnectionHandler.deleteNode(
conn,
deletedID
)
}
function commit (environment, user, viewer, config) {
return commitMutation(
environment,
{
mutation,
variables: {
input: {
id: user.id
}
},
updater: (store) => {
const payload = store.getRootField('UserRemove')
const deletedID = payload.getValue('deletedID')
sharedUpdater(store, viewer, deletedID)
},
optimisticUpdater: (store) => {
sharedUpdater(store, viewer, user.id)
},
onCompleted: config.onCompleted,
onError: config.onError
}
)
}
export default {commit}
And here's the error:

If I console.log the const conn, it returns me null. I've checked my fragment and the @connection is correct:
viewer: graphql`
fragment users_list_datatalist_viewer on Viewer {
id
users(first: $first, search: $search) @connection(key: "list_users") {
edges {
node {
id
name
email
}
}
pageInfo {
hasNextPage
}
}
}
`
Am I doing something wrong?
Thanks!
My guess is that you should do one of these:
@connection(key: "list_users", filters: [])
or:
const conn = ConnectionHandler.getConnection(
viewerProxy,
'list_users',
{search: "a particular query"}
)
Does your viewer type have an id field? There is a bug that causes data duplication for the viewer object when it has an id field, it might explain this. Although try @miracle2k's suggestions too!
Just a note:
@connection(key: "list_users", filters: []) means: store the data regardless of the value of search -- this could cause a potential problem if there are two components/views sharing the same connection and when the second view fetches the connection with search: "foo", it will overwrite the data fetched with search: bar in the first view.
@miracle2k
The first one makes sense in my case, and worked like a charm... Thanks!
@josephsavona
Yeah, the viewer type does have an id. Adding filters: [] to @connection fixed my problem... Anything I could do to help, if this issue match? Or may I close it? Thanks!
@JenniferWang
For now I don't have any components sharing connections, so, I don't think it's gonna be a problem. Thanks!
I am having a problem getting a value for ConnectionHandler.getConnection(). Perhaps the concept of viewer is blowing my mind, but I can't figure out what value is supposed to be the first argument.
updater: (store) => {
const payload = store.getRootField('addComment');
const newComment = payload.getLinkedRecord('commentEdge');
const storeRoot = store.getRoot();
const connection = ConnectionHandler.getConnection(storeRoot, 'Comments_results');
...
}
Here's my @connection: https://github.com/staylor/wp-relay-app/blob/modern-relay/src/components/Comments/Comments.js#L18
Mutation: https://github.com/staylor/wp-relay-app/blob/modern-relay/src/components/Comments/Comments.js#L66
As you can see, I have no Viewer. This is all confusing. Help?
@JenniferWang @miracle2k what's the difference between @connection(key: "list_users") and @connection(key: "list_users", filters: []) ? I thought if you skip filters , it defaults to []
@bochen2014 If you don't specify the filters, it defaults to all arguments used, IIRC from reading the source.
I have a fragment
fragment item_viewer on viewer {
id,
shopItems(first:$first,last:$last,ShopId:$ShopId,SubCategoryId:$SubCategoryId) @connection(key: "item_shopItems", filters:[]) {
pageInfo {
hasNextPage
endCursor
}
edges {
cursor
node {
id
name
price
}
}
}
}
when I do,
const conn = ConnectionHandler.getConnection(this.props.viewerId,'item_shopItems', [])
console.log(conn) // null
the connection handler returns null. Don't know what I'm doing wrong
you need to use @connection directive
its there
Is there a server side config for @connection too or you just have to use it in the fragment?
const storeRoot = store.getRoot();
const connection = ConnectionHandler.getConnection(storeRoot, 'Comments_results');
I think you need to use your storeRoot, instead of this.props.viewerId
tried that already, returns undefined. Why store.getRoot when I'm using viewer?
I am having the same issue as i am getting "connection" as undefined if i do :
const storeRoot = store.getRoot();
const connection = ConnectionHandler.getConnection(storeRoot, 'Comments_results');
Any Idea how to proceed?. I am stuck here as my list is not getting updated in UI
Can u share more code? Which node is the parent of this connection?
This is my mutation:
mutation CreateChatMutation($input: CreateChatInput!){
createChat(input: $input){
chat{
id
from
content
createdAt
}
}
}
This is my updater.
{
updater: proxyStore => {
// 1 - retrieve the `newPost` from the server response
const createPostField = proxyStore.getRootField('createChat')
const newPost = createPostField.getLinkedRecord('chat')
// 2 - add `newPost` to the store
const viewerProxy = proxyStore.getRoot()
const connection = ConnectionHandler.getConnection(viewerProxy, 'LinkList_allChats', {
last: 100,
orderBy: 'createdAt_ASC'
})
console.log('updater: connection : ',connection);
if (connection) {
ConnectionHandler.insertEdgeAfter(connection, newPost)
}
}
Is your connection inside Viewer or Query?
If it is inside viewer you need to pass your viewer id, if it is inside query, you need to get ROOT_ID from relay runtime
I am not sure what you meant. I am attaching the code of CreateChat.js. I am also attaching LinkList.js which i am using in CreateChat.js. Can you please elaborate.?
import React, {Component} from 'react'
import CreateChatMutation from './CreateChatMutation'
import {
QueryRenderer,
graphql
} from 'react-relay'
import environment from './Environment'
import LinkList from './LinkList'
import Link from './Link'
import NewChatSubscription from './NewChatSubscription'
const CreateChatQuery = graphql`
query CreateChatQuery {
viewer {
...LinkList_viewer
}
}
`
var refetching = true;
class CreateChat extends Component {
state = {
from:'',
content:''
}
componentDidMount() {
// Get username form prompt
// when page loads
// const {froms, content} = this.state
const from = window.prompt('username');
from && this.setState({ from });
NewChatSubscription()
}
render() {
return (
<div>
<div>
<QueryRenderer
environment={environment}
query={CreateChatQuery}
variables={{refetch: refetching}}
render={({error, props}) => {
if (error) {
return <div>{error.message}</div>
} else if (props) {
return <LinkList viewer={props.viewer} />
}
return <div>Loading</div>
}}
/>
</div>
<div>
<div className='flex flex-column mt3'>
<input
className='mb2'
value={this.state.content}
onChange={(e) => this.setState({ content: e.target.value })}
type='text'
placeholder='Message'
/>
</div>
<div
className='button'
onClick={() => this._createLink()}>
submit
</div>
</div>
</div>
)
}
_createLink = () => {
const {from, content} = this.state
CreateChatMutation(from, content, (response)=>
{refetching = false;
console.log('refetch: '+refetching);
})
}
}
export default CreateChat
This is my LinkList.js which i am using in CreateChat.js:
import React, {Component} from 'react'
import Link from './Link'
import {createFragmentContainer, graphql} from 'react-relay'
class LinkList extends Component{
render() {
return(
<div>
{
this.props.viewer.allChats.edges.map(({node}) =>
<Link key={node.__id} link={node}/>
)}
</div>
)
}
}
export default createFragmentContainer(LinkList, graphql`
fragment LinkList_viewer on Viewer{
allChats(last: 100, orderBy: createdAt_ASC) @connection(key:"LinkList_allChats", filters:[]){
edges{
node{
...Link_link
}
}
}
}`)
Most helpful comment
My guess is that you should do one of these:
or: