Reputation: 7966
Summary: My problem is that when I create a node using a Relay
mutation, the mutation creates the record in my database, but my client-side local data isn't updating, and the query response appears to be missing the new node.
Discussion: I think the RANGE_ADD
should add the new node, ListingRating
, to my local collection of ListingRating
s, which should automatically update the connected nodes (Listing
and User
). However, according to the relay
panel in react-dev-tools
, the mutation doesn't include any of the fields I need updated.
Questions:
Should RANGE_ADD
be sufficient here? If so, what's wrong with my implementation?
Do I have to update the Listing
and User
nodes manually? If so, how? Those nodes are only available deeply nested in the mutation payload
, and FIELDS_CHANGE
requires a fieldId
in the top-level of the payload
, right?
Schema: My schema holds Listing
s (adverts), User
s, and Rating
s (users' ratings of those Listings
). it looks something like this:
type Listing = {
...
ratings: [ListingRating]
}
type User = {
...
ratings: [ListingRating]
}
type ListingRating = {
rating: Int
user: User
listing: Listing
}
Mutation: I'm using scaphold.io as a back end, so don't have control over the mutation structures (though they're to Relay spec). They look like this:
mutation createListingRating(input: CreateListingRatingInput!) { CreateListingRatingPayload }
// CreateListingRatingInput
{
listingId: ID
listing: CreateListingInput
rating: Int
userId: ID
user: CreateUserInput
clientMutationId: ID
}
// CreateRatingPayload
{
changedListingRating: ListingRating
changedEdge: ListingRatingEdge
viewer: Viewer
clientMutationId: String
}
Relay mutation:
export default class CreateListingRating extends Relay.Mutation {
getMutation() {
return Relay.QL`
mutation {
createListingRating
}
`
}
getVariables() {
return {
userId: this.props.userId,
listingId: this.props.listingId,
rating: this.props.newRating,
}
}
getFatQuery() {
return Relay.QL`
fragment on CreateListingRatingPayload @relay(pattern: true){
changedEdge
changedListingRating {
listing
user
rating
}
viewer
}
`
}
getConfigs() {
return [{
type: 'RANGE_ADD',
parentID: this.props.viewer.id,
parentName: 'viewer',
connectionName: 'allListingRatings',
edgeName: 'changedEdge',
rangeBehaviors: {
'': 'append',
},
}]
}
}
Query: (not sure this is relevant) In my app, the query I use to display the ListingRating
s goes something like this:
query {
getUserGroup(id: 'some-group-id') {
users {
edges {
node {
listings {
edges {
node {
ratings {
edges {
node {
rating
}
}
}
}
}
}
}
}
}
}
}
Mutation request: (ie, what displays in the relay panel in react-dev-tools)
mutation CreateListingRating($input_0:CreateListingRatingInput!) {
createListingRating(input:$input_0) {
...F1
,
clientMutationId
}
}
fragment F0 on Viewer {
id,
user {
firstName
,
id
}
}
fragment F1 on CreateListingRatingPayload {
viewer {
...F0
}
}
Upvotes: 0
Views: 497
Reputation: 7966
I abandoned the method above and decided to go with the Relay.GraphQLMutation
API, as suggested by the Relay docs to get ready for the Relay 2.0
API.
I can't say what the problem was in my OP, but conceptually, my problem was that I was adding a node to my UI, but failing to explicitly fetch the parent (ie, I was adding a ListingRating
, but not updating the Listing
, which, in my app, was the parent that rendered the ListingRating
).
The github issue here &-one of the latest comments by nodzk
were the ticket. here's my code:
import ListingRelayContainer from 'components/Listing
const Rating = (props, context) => {
const _createListingRating = (input) => {
createRating(input, context.relay)
}
// ...render etc
}
// this API requires a `Relay Environment`, so pull
// ours from context to avoid making anew
Rating.contextTypes = {
relay: Relay.PropTypes.Environment,
}
const createRating = (variables, relayStore) => {
const query = Relay.QL`mutation {
createListingRating(input:$input) {
changedListingRating {
rating
id
listing {
${ListingRelayContainer.getFragment('listing')}
}
}
}
}
`
const input = { input: variables }
const mutation = new Relay.GraphQLMutation(
query,
input,
null, // No files.
relayStore,
{
onFailure: err => console.warn(err),
onSuccess: () => console.log('Success!'),
},
)
mutation.commit()
}
Bing-bang-boom, all updated (though no optimistic update yet).
Notice we didn't even have to get into config
(eg, RANGE_ADD
). note that if we had wanted to fuss with config
, we would have passed an object to mutation.commit()
.
The important part here is including the fragment
from Listing
. This ensures that the collection of ratings on the listing is updated to include the newly created Rating
.
Upvotes: 0