Managing states in React apps with Apollo Client: execute queries

Communicate to APIs is most important thing in apps for accessing information stored in databases or something else, we have two options to get this data: Rest Api or Graphql Api, in This article we cover how to fetch data with Graphql using Apollo client.

Prerequisites:

  • Familiar with building basic GraphQL Documents and Fragments
  • Reading the previous article

With Apollo Client you can fetch data when the component is mounted or when you make specific action with smart APIs that cache those queries out of the box.

How🤔? apollo client provides flexible hooks that make those operations easier

useQuery vs useLazyQuery:

To execute graphql document, Apollo Client provides React hooks that help you, with tracking errors and loading states.

import { gql, useQuery } from '@apollo/client'
const GET_TODOS = gql`
  query getTodos {
    todos {
      id
      label
    }
  }
`
const TodosView = () => {
  const { data, loading, error } = useQuery(GET_TODOS)
  if (loading) return <>we loading the data🌝</>
  if (error) return <>Opps! something is wrong:{error.message}</>
  return (
    <div>
      {React.Children.toArray(
        data.todos.map((todo) => <span>{todo.label}</span>)
      )}
    </div>
  )
}

The example above explains how we can execute graphql document when the component is mounted. Remember You need to wrap your graphql document with gql function to parse into query. what about if you want to execute query when you click on the button or something like this? with Apollo you can do it by using useLazyQuery:

import { gql, useLazyQuery } from '@apollo/client'
const GET_TODOS = gql`
  query getTodos {
    todos {
      id
      label
    }
  }
`
const TodosView = () => {
  const [getTodos, { loading, error, data }] = useLazyQuery(GET_TODOS)
  if (loading) return <>we loading the data🌝</>
  if (error) return <>Opps! something is wrong:{error.message}</>
  return (
    <div>
      <button
        onClick={() => {
          getTodos()
        }}
      >
        Lemme Show Tasks
      </button>
      {React.Children.toArray(
        data.todos.map((todo) => <span>{todo.label}</span>)
      )}
    </div>
  )
}

useLazyQuery returns array that contains executor query function in first item, in second item of array we have object that contains data, loading and error states.

but how we can pass variables to graphql documents ?

no worries 😅, useQuery accept the second param as variables for graphql document look 👇:

import { gql, useQuery } from '@apollo/client'
const GET_TODO = gql`
  query getTodo($id: ID) {
    todo(id: $id) {
      label
      status
    }
  }
`
const SingleTodo = () => {
  const { data, loading, error } = useQuery(GET_TODO, {
    variables: { id: 10 },
  })
  if (loading) return <>we loading the data🌝</>
  if (error) return <>Opps! something is wrong:{error.message}</>
  return (
    <div>
      <span>{data.todo.label}</span>
    </div>
  )
}
export default { SingleTodo }

also with useLazyQuery can you do like this:

import { gql, useLazyQuery } from '@apollo/client'
const GET_TODO = gql`
  query getTodo($id: ID) {
    todo(id: $id) {
      label
      status
    }
  }
`
const SingleTodo = () => {
  const [getTodo, { loading, error, data }] = useLazyQuery(GET_TODO)
  if (loading) return <>we loading the data🌝</>
  if (error) return <>Opps! something is wrong:{error.message}</>
  return (
    <div>
      <button
        onClick={() => {
          getTodo({ variables: { id: 10 } })
        }}
      >
        show task
      </button>
      <div>
        <span>{data.todo.label}</span>
      </div>
    </div>
  )
}
export default { SingleTodo }

conclusion:

Apollo Client provides hooks out of the box that help you do make fetching easier, now we need to cache those queries and re-use them without refetching again and again. that's what we cover in the next article.