简体   繁体   中英

How do I update connected Nodes in a RANGE_ADD mutation?

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

  }

}

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM