Tying Data to Components with GraphQL Fragments
Giant queries are hard to maintain. When a parent query fetches data for every child component, the code becomes brittle. If you change a child component, you have to find and update the parent query too.
You can fix this by using GraphQL fragments. This lets each component own its data requirements.
How it works
Using urql and graphql-codegen, you can define a fragment right next to your component.
1. The Author Card
The AuthorCard only needs a name and an avatar. We define that in a fragment.
// AuthorCard.tsx
export const AuthorFragment = graphql(/* GraphQL */ `
fragment AuthorDetails on User {
name
avatarUrl
}
`);
export const AuthorCard = (props: { user: FragmentType<typeof AuthorFragment> }) => {
const user = useFragment(AuthorFragment, props.user);
return (
<div>
<img src={user.avatarUrl} />
<span>{user.name}</span>
</div>
);
};
2. Nesting Fragments
A Comment component needs its own text, but it also uses the AuthorCard. It just includes the author's fragment.
// Comment.tsx
export const CommentFragment = graphql(/* GraphQL */ `
fragment CommentDetails on Comment {
body
author {
...AuthorDetails
}
}
`);
export const Comment = (props: { comment: FragmentType<typeof CommentFragment> }) => {
const comment = useFragment(CommentFragment, props.comment);
return (
<div>
<p>{comment.body}</p>
<AuthorCard user={comment.author} />
</div>
);
};
3. The Parent Query
The main blog post query doesn't need to know which fields the author or comments use. It just spreads the fragments.
// BlogPost.tsx
const PostQuery = graphql(/* GraphQL */ `
query GetPost($id: ID!) {
post(id: $id) {
title
author { ...AuthorDetails }
comments { ...CommentDetails }
}
}
`);
Why this is better for your workflow
This setup changes how you handle updates.
Change once, update everywhere: If you need to add a "Twitter handle" to the author card, you only edit AuthorCard.tsx.
Automatic updates: The codegen watcher sees the change. It automatically updates the parent query to fetch that new field. You don't have to touch BlogPost.tsx at all.
Safety: TypeScript will prevent you from using data you didn't ask for. If the Comment component tries to use the author's bio but didn't put it in the fragment, the code won't compile.
Less hunting: You don't have to search through files to see where data comes from. It's always defined right where it's used.
And that is it. It keeps your components independent and your queries clean. You can see the full setup in the urql documentation.