In this post we cover how to use Apollo useQuery with multiple queries
How to use Apollo useQuery with multiple queries
When using Apollo useQuery in React applications, you will occasionally want to make multiple queries or mutations.
The best route to take, if possible, is to include the extra fields in your GraphQL query string.
When that is not an option you can make use of the skip
property within the useQuery hook.
The skip property enables you to control when a query is fired which means you can wait for props or variables before triggering a query request.
1import React from 'react';
2import gql from 'graphql-tag';
3import { useQuery } from '@apollo/client';
4
5const CoffeeQuery = gql`
6 query coffeeQuery($coffeeType: CoffeeType!) {
7 coffee(coffeeType: $coffeeType) {
8 id
9 name
10 }
11 }
12`
13
14const FoodPairingQuery = gql`
15 query foodPairingQuery($coffeeId: ID!) {
16 foodPairing(coffeeId: $coffeeId) {
17 name
18 }
19 }
20`
21
22export default function FoodPairingSuggestion({ coffeeType }) {
23 const coffee = useQuery(CoffeeQuery, {
24 variables: { coffeeType },
25 skip: !coffeeType,
26 notifyOnNetworkStatusChange: true
27 });
28
29 const food = useQuery(FoodPairingQuery, {
30 variables: { coffeeId: coffee.data?.coffee?.id },
31 skip: coffee.loading || !coffee.data?.coffee?.id,
32 notifyOnNetworkStatusChange: true
33 });
34
35 const errors = coffee.error || food.error;
36 const loading = coffee.loading || food.loading;
37
38 const refetchAll = async () => {
39 await coffee.refetch();
40 await food.refetch();
41 };
42
43 if (loading) {
44 return <p>loading...</p>;
45 }
46
47 return (
48 <div>
49 {errors && <h3 style={{ color: 'red' }}>{errors}</h3>}
50 <p>
51 {coffee.data?.coffee?.name}
52 </p>
53 <p>
54 {food.data?.food?.name}
55 </p>
56 <button onClick={refetchAll}>Refetch</button>
57 </div>
58 );
59}
In the above code you can see that the component accepts a coffee type as a prop which is passed into the first query to get the id of the coffee. Once we have that id we then make a second request to get the food pairing to go with it.
Both queries make use of the "skip" property to only be triggered at the appropriate moments.
Where possible an alternative solution here is to resolve these fields in your GraphQL server instead which would simplify the code significantly by allowing you to make a single request on the frontend and resolve everything in the backend/server side.
1import React from 'react';
2import gql from 'graphql-tag';
3import { useQuery } from '@apollo/client';
4
5const CoffeeQuery = gql`
6 query coffeeQuery($coffeeType: CoffeeType!) {
7 coffee(coffeeType: $coffeeType) {
8 id
9 name
10 foodPairing {
11 name
12 }
13 }
14 }
15`
16export default function FoodPairingSuggestion({ coffeeType }) {
17 const coffee = useQuery(CoffeeQuery, {
18 variables: { coffeeType },
19 skip: !coffeeType,
20 notifyOnNetworkStatusChange: true
21 });
22
23 if (coffee.loading) {
24 return <p>loading...</p>;
25 }
26
27 return (
28 <div>
29 {coffee.errors && <h3 style={{ color: 'red' }}>{coffee.errors}</h3>}
30 <p>
31 {coffee.data?.coffee?.name}
32 </p>
33 <p>
34 {coffee.data?.coffee?.foodPairing?.name}
35 </p>
36 <button onClick={coffee.refetch}>Refetch</button>
37 </div>
38 );
39}
To summarise how to use Apollo useQuery with multiple queries wherever possible allow the server to do the heavy lifting by being able to resolve related fields and then include them in the same query string. When that is not an option make use of the "skip" field accepted in the useQuery hook params.
React
React or ReactJs is a library used for developing frontend applications. Its main concepts are based around state, props, and renders.
When a state variable or prop gets updated or changed, they trigger a render.
When a render happens the appropriate parts of the application essentially get re-built using the new values to provide a new UI to the user.
It is worth noting that a prop that causes a render is just a state variable that gets passed into another component.
GraphQL
GraphQL is a query language that provides a number of ways that bring improvements when it comes to accessing data.
There are two sides to GraphQL.
On the frontend you will structure your requests in the shape of a graph laid out in a semi JSON style format where you request fields by naming each one you need in the shape they exist in.
On the backend or server side you create these shapes via a schema and ensure that when requested they are sent in the agreed upon shape.
There are many powerful features, such as resolving with id's, only requesting/sending the data that is requested, patching together various API's and so on.
Further resources
Related topics
Save code?