useQuery Hook
In this section, we will implement GraphQL Queries and integrate with the react UI. With Apollo Client, you can send queries in 3 different ways.
- Using the
client.query
method directly and then process the response. - Render Prop API with React.
- Using the
useQuery
hook. (Recommended)
Apollo useQuery Hook
The recommended method is to use the useQuery
hook, where you will just wrap your GraphQL query to the gql
function and will fetch the data automatically and will give a result object containing data, loading and error properties.
Great! Now let's define the graphql query to be used:
Open src/components/Todo/TodoPrivateList.tsx
and add the following code:
import React, { Fragment, useState } from "react";+ import { gql } from "@apollo/client";import TodoItem from "./TodoItem";import TodoFilters from "./TodoFilters";+ export const GET_MY_TODOS = gql`+ query getMyTodos {+ todos(where: { is_public: { _eq: false} }, order_by: { created_at: desc }) {+ id+ title+ is_completed+ }+ }`;type Todo = {id: number,title: string,is_completed: boolean};
We have now written the graphql query as a javascript constant using the gql
parser function. This function is used to parse the plain string as a graphql query.
The query is now ready, let's integrate it with our react code.
import React, { Fragment, useState } from "react";- import { gql } from "@apollo/client";+ import { gql, useQuery } from "@apollo/client";
useQuery
hook is being imported from @apollo/react-hooks
import React, { Fragment, useState } from "react";import { gql, useQuery } from "@apollo/client";import TodoItem from "./TodoItem";import TodoFilters from "./TodoFilters";export const GET_MY_TODOS = gql`query getMyTodos {todos(where: { is_public: { _eq: false} }, order_by: { created_at: desc }) {idtitlecreated_atis_completed}}`;type Todo = {id: number,title: string,is_completed: boolean,is_public: boolean};const TodoPrivateList = () => {const [filter, setFilter] = useState<string>("all");+ const { loading, error, data } = useQuery(GET_MY_TODOS);......const clearCompleted = () => {};+ if(loading) {+ return (<div>Loading...</div>);+ }+ if(error || !data) {+ return (<div>Error...</div>);+ }- let filteredTodos = todos;+ let filteredTodos = data.todos;if (filter === "active") {- filteredTodos = todos.filter((todo: Todo) => todo.is_completed !== true);+ filteredTodos = data.todos.filter((todo: Todo) => todo.is_completed !== true);} else if (filter === "completed") {- filteredTodos = todos.filter((todo: Todo) => todo.is_completed === true);+ filteredTodos = data.todos.filter((todo: Todo) => todo.is_completed === true);}......return (...);}export default TodoPrivateList;export { GET_MY_TODOS };
With the useQuery
hook from @apollo/react-hooks
and the graphql query we defined above, we fetch the todo data.
Let's remove the mock todos
data which was used to populate sample data.
const TodoPrivateList = () => {const [filter, setFilter] = useState<string>("all");const { loading, error, data } = useQuery(GET_MY_TODOS);- const todos = [- {- id: 1,- title: "This is private todo 1",- is_completed: true- },- {- id: 2,- title: "This is private todo 2",- is_completed: false- }- ];const filterResults = (filter: string): void => {setFilter(filter);};...
Woot! You have written your first GraphQL integration with React and Typescript. Easy isn't it?
How does this work?
The useQuery
hook returned a result object containing the following:
loading
: A boolean that indicates whether the request is in flight. If loading is true, then the request hasn't finished. Typically this information can be used to display a loading spinner.
error
: A runtime error with graphQLErrors and networkError properties. Contains information about what went wrong with your query.
data
: An object containing the result of your GraphQL query. This will contain our actual data from the server. In our case, it will be the todo data.
You can read more about other values that Apollo returns in the result object here
Using the data
prop, we are parsing the results from the server. In our query, data
prop has an array of todos
which can be mapped over to render each TodoItem
.
If you noted, there has been some client side filtering to the todos that are displayed.
- Build apps and APIs 10x faster
- Built-in authorization and caching
- 8x more performant than hand-rolled APIs