I am a big Relay fan, but I have always been curious about Apollo client, so recently I started to learn it on a new side project. I have had a great experience, but one big difference is how Apollo uses fragments.
What are Fragment Driven UIs?
Fragment Driven UIs lets us declare our data in each component, giving us a quick glance about the data that is required by the component, reducing prop drilling as well as being less error prone.
Here is a quick example from the Relay documentation
type Props = {|
user: UserComponent_user$key,
|};
function UserComponent(props: Props) {
const data = useFragment(
graphql`
fragment UserComponent_user on User {
name
profile_picture(scale: 2) {
uri
}
}
`,
props.user,
);
return (
<>
<h1>{data.name}</h1>
<div>
<img src={data.profile_picture?.uri} />
</div>
</>
);
}
You can easily see the data the component needs, and the only thing we have to do to meet the component data requirements is to pass down the user key prop. Here is a quick example demostrating the parent component for UserComponent
type Props = {|
id: string,
|};
function UserPage({id}: Props) {
const data = useLazyLoadQuery(
graphql`
query User($id: ID!) {
user(id: $id) {
...UserComponent_user
}
}
`,
{id} ,
);
return (
<UserComponent user={data.user} />
);
}
No matter how big the query your component needs, you will always only pass down one prop for it. This helps large teams move quicker and easier.
Moving to Apollo
I am using Typescript as well as GraphQL Code Generator, here is my codegen.yml
overwrite: true
schema: 'http://localhost:4000/graphql'
documents: '{pages,components,graphql}/**/*.{ts,tsx}'
generates:
generated/graphqlComponents.tsx:
plugins:
- 'typescript'
- 'typescript-operations'
- 'typescript-react-apollo'
This will generate graphql types for the graphql tags that are on pages, components or graphql folders.
This is a Fragment UI Component in Apollo
type Props = {
data: UserAvatar_UserFragment;
};
const UserAvatar = ({ data }: Props) => {
return (
<Flex alignItems="center">
<Link href={`/u/${data.username}`}>
<a>
<Text fontWeight="700">
{data.username}
</Text>
</a>
</Link>
</Flex>
);
};
UserAvatar.USER_AVATAR_FRAGMENT = gql`
fragment UserAvatar_user on User {
username
}
`;
This is quite similiar to Relay, but instead of passing down a key to the fragment reference, we pass down the fragment data, that will be present in our parent componen, this data type comes from our GraphQL Code Gen.
const COLLECTION_QUERY = gql`
query Collection($id: ID!) {
collection(id: $id) {
user {
...UserAvatar_user
}
}
}
`;
const CollectionPage = () => {
const router = useRouter();
const { data } = useCollectionQuery({ variables: { id: router.query.id } });
return (
<UserAvatar data={data.collection.user} />
);
};
We use the Query hook generated from the Code Gen and we pass down the data props to our child component. Making a similar dev experience to Relay, while also having the freedom from Apollo!
Thank you for reading, I hope you could find this useful! Comment down below if you have any doubts or want to know more about Relay!
Top comments (1)
Awesome post Hector! Looking forward to seeing more GraphQL!