Queries and Mutations
Queries read data. Mutations change data.
In React, the important skill is connecting these operations to loading states, variables, errors, cache updates, and user feedback.
Query Basics
query GetProduct($id: ID!) {
product(id: $id) {
id
name
price
}
}Variables keep operations reusable and safe.
{
"id": "p1"
}Avoid building query strings with user input.
Field Selection
Request the fields the component needs.
query ProductCard($id: ID!) {
product(id: $id) {
id
name
thumbnailUrl
price
}
}If another screen needs reviews, use a different operation or fragment.
Fragments
Fragments reuse field selections.
fragment ProductSummary on Product {
id
name
price
}
query ProductPage($id: ID!) {
product(id: $id) {
...ProductSummary
description
}
}Fragments are useful, but avoid creating huge fragments that every screen imports blindly.
Mutation Basics
Mutations should return the changed data the client needs.
mutation RenameProject($id: ID!, $name: String!) {
renameProject(id: $id, name: $name) {
id
name
updatedAt
}
}Returning id and changed fields helps normalized caches update correctly.
Input Objects
For larger mutations, use input objects.
input CreateLessonInput {
courseId: ID!
title: String!
body: String!
}
mutation CreateLesson($input: CreateLessonInput!) {
createLesson(input: $input) {
id
title
}
}This keeps operation signatures manageable as inputs grow.
Handling Errors
GraphQL has transport-level errors and GraphQL operation errors.
Examples:
- network is offline
- server returns
500 - validation error in the GraphQL response
- partial data with field errors
- authorization error for one field
Your React UI should distinguish:
- cannot reach server
- user input is invalid
- user lacks permission
- data partially loaded
Optimistic Mutations
An optimistic mutation updates UI before the server responds.
renameProject({
variables: { id, name },
optimisticResponse: {
renameProject: {
__typename: "Project",
id,
name,
updatedAt: new Date().toISOString(),
},
},
});Use optimistic updates for reversible, low-risk actions. Be careful with payments, inventory, and destructive operations.
Pagination
GraphQL lists still need pagination.
Common styles:
- offset pagination
- cursor pagination
- connection-style pagination
query ProjectList($after: String) {
projects(first: 20, after: $after) {
edges {
cursor
node {
id
name
}
}
pageInfo {
hasNextPage
endCursor
}
}
}Cursor pagination is often better for changing lists.
Common Mistakes
- Omitting
idfrom mutation responses. - Requesting huge nested lists without pagination.
- Using one giant query for every screen.
- Ignoring partial data and GraphQL errors.
- Treating all mutations as safe for optimistic UI.
- Forgetting that authorization must be checked on the server.
Why should mutation responses often include id and changed fields?
Practical Challenge
Write GraphQL operations for a lesson comments feature.
Include:
- query comments with pagination
- mutation to add a comment
- mutation to edit a comment
- mutation to delete a comment
- fields needed for cache updates
- possible validation and authorization errors
Recap
Queries and mutations are more than syntax. They define data shape, cache behavior, error handling, and UI state.
Use variables, focused field selections, pagination, and mutation responses that help the client stay consistent.