Fetching GraphQL Data with useQuery

Apollo Client's useQuery hook connects a React component to a GraphQL query.

For example:

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

A component can use it:

const { data, loading, error } = useQuery(GET_USER, {
  variables: { id }
});

The component should account for at least three broad states:

Loading
   ↓
Success ─────→ Render data
   ↓
Error ───────→ Render error state

A production component should not assume data exists immediately.

For example:

if (loading) return <Spinner />;
if (error) return <ErrorMessage />;
if (!data?.user) return <NotFound />;

return <UserProfile user={data.user} />;

The exact UI depends on the application, but the important concept is that server state is asynchronous and can change independently of the component lifecycle.

React Query Component
const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

function UserProfile({ id }) {
  const { data, loading, error } = useQuery(GET_USER, {
    variables: { id }
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Failed to load user.</p>;
  if (!data?.user) return <p>User not found.</p>;

  return <h1>{data.user.name}</h1>;
}
💡 The query declares an ID variable and requests the user fields required by the component. The component explicitly handles loading, error, missing-data, and success states.
Key Takeaways
  • useQuery connects a React component to a GraphQL query.
  • Variables are passed separately from the GraphQL document.
  • Components should handle loading and error states.
  • Server data should not be assumed to exist immediately.
Knowledge Check

Which state should a React component generally consider when using `useQuery`?