DEV Community 👩‍💻👨‍💻

Cover image for Fragment Driven UIs with Apollo
Hector de Luna
Hector de Luna

Posted on

Fragment Driven UIs with Apollo

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>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

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} />
  );
}
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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
  }
`;
Enter fullscreen mode Exit fullscreen mode

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} />
  );
};
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
arturotorres profile image
Arturo Torres

Awesome post Hector! Looking forward to seeing more GraphQL!

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.