Skip to content

Commit 5e62f60

Browse files
unicodeveloperpeggyrayzis
authored andcommitted
Add content
1 parent 884052c commit 5e62f60

1 file changed

Lines changed: 153 additions & 2 deletions

File tree

docs/source/tutorial/queries.md

Lines changed: 153 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,162 @@ You have learned how to fetch data with Apollo Client. In this section, you'll d
99

1010
Fetching data in a simple, predictable and optimistic way is one of the core features of Apollo Client. `react-apollo`, a view layer integration for Apollo Client, exports a `Query` React component that allows you pass a GraphQL query string wrapped with the `gql` tag to a `query` prop.
1111

12-
The `Query` component uses the render prop pattern
13-
12+
The `Query` component uses the render prop pattern to fetch and load data from queries into our React UI. The render prop pattern provides the ability to add a function as a child to our `Query` component that will notify React about what you want to render. The `Query` component exposes the `error`, `loading` and `data` state properties that you can use to determine the type of UI to render depending on the state of the query.
1413

1514
<h2 id="fetch-data">Fetch data with Query</h2>
1615

16+
Let's create a query and fetch data with the `Query` component.
17+
18+
Navigate to `src/components` directory and create a `launch-list.js` file. Copy the code below and add to it.
19+
20+
_src/components/launch-list.js_
21+
22+
```js
23+
import React from 'react';
24+
import { Query } from 'react-apollo';
25+
import gql from 'graphql-tag';
26+
import styled from 'react-emotion';
27+
28+
const LIST_LAUNCHES = gql`
29+
query launchList($after: String) {
30+
isLoggedIn @client
31+
launches(after: $after) {
32+
cursor
33+
hasMore
34+
launches {
35+
isBooked
36+
id
37+
year
38+
rocket {
39+
name
40+
}
41+
mission {
42+
name
43+
missionPatch
44+
}
45+
}
46+
}
47+
}
48+
`;
49+
50+
51+
export default class LaunchList extends React.Component {
52+
render() {
53+
return (
54+
<Query query={LIST_LAUNCHES}>
55+
{({ data, loading, error }) => {
56+
if (loading) return <p>Loading...</p>;
57+
if (error) return <p>ERROR</p>;
58+
59+
return (
60+
<Container>
61+
{data.launches && data.launches.launches
62+
? data.launches.launches.map(l => (
63+
<LaunchTile
64+
key={l.id}
65+
launch={l}
66+
isLoggedIn={data.isLoggedIn}
67+
/>
68+
))
69+
: null}
70+
</Container>
71+
);
72+
}}
73+
</Query>
74+
);
75+
}
76+
}
77+
78+
const Container = styled('div')({
79+
marginBottom: '16px',
80+
width: '100%',
81+
});
82+
83+
const LoadMoreButton = styled('button')({
84+
backgroundColor: '#00194b',
85+
border: 'none',
86+
color: 'white',
87+
padding: '15px 32px',
88+
textAlign: 'center',
89+
textDecoration: 'none',
90+
display: 'inline-block',
91+
fontSize: '16px',
92+
});
93+
```
94+
95+
**Note:** We used `react-emotion` for styling. Make sure the `react-emotion` package is installed.
96+
97+
To fetch data using the `Query` component, a query string needs to be passed to the `query` prop. The `LIST_LAUNCHES` query was passed to the `query` prop of the `Query` component to fetch a list of all the launches.
98+
99+
The `Query` component uses a render prop pattern, so we passed a function as a child to the component that contains what React will render to the screen. The `Query` component provides us with a `loading`, `error`, and `data` property that keeps the user informed about the status of the query operation on the screen. If it's in a loading state, the user sees **Loading...** on the screen. If there's an error, the user sees **ERROR** on the screen.
100+
101+
If the data was returned successfully, then the launches are retrieved from the `data` property and displayed on the screen via the `LaunchTile` component.
102+
103+
Now, there are a lot of launches. If all the launches are fetched at once and displayed, the result will be a long undesirable list. Therefore, let's build a pagination feature that accomodates the loading of a few items at once and display a `Load More` button for loading more items on the screen.
104+
17105
<h2 id="pagination">Build a paginated list</h2>
18106

107+
There are different approaches to building a paginated list. You'll build a pagination feature using the `cursor-based` approach. The cursor keeps track of where in the data set the next items should be fetched from.
108+
109+
In the code below, we use a `fetchMore` query to continuously load new launches, which will be prepended to the list. The cursor to be used in the fetchMore query is provided in the initial server response, and is updated whenever more data is fetched.
110+
111+
Copy the code below and add to the `LaunchList` class.
112+
113+
```js
114+
<Query query={LIST_LAUNCHES}>
115+
{({ data, loading, error, fetchMore }) => {
116+
if (loading) return <p>Loading...</p>;
117+
if (error) return <p>ERROR</p>;
118+
119+
return (
120+
<Container>
121+
{data.launches && data.launches.launches
122+
? data.launches.launches.map(l => (
123+
<LaunchTile
124+
key={l.id}
125+
launch={l}
126+
isLoggedIn={data.isLoggedIn}
127+
/>
128+
))
129+
: null}
130+
{data.launches && data.launches.hasMore ? (
131+
<LoadMoreButton
132+
onClick={() =>
133+
fetchMore({
134+
variables: {
135+
after: data.launches.cursor,
136+
},
137+
updateQuery: (prev, { fetchMoreResult, ...rest }) => {
138+
if (!fetchMoreResult) return prev;
139+
return {
140+
...fetchMoreResult,
141+
launches: {
142+
...fetchMoreResult.launches,
143+
launches: [
144+
...prev.launches.launches,
145+
...fetchMoreResult.launches.launches,
146+
],
147+
},
148+
};
149+
},
150+
})
151+
}
152+
>
153+
Load More
154+
</LoadMoreButton>
155+
) : null}
156+
</Container>
157+
);
158+
}}
159+
</Query>
160+
```
161+
162+
The easiest way to go about pagination with Apollo is with the `fetchMore` function which is provided as a property by the `Query` component. By default, 20 launches are returned at once. Why 20? The paginate helper function in the `src/utils.js` file accepts a page size of 20 if no argument was passed to specify the number of launches to return.
163+
164+
The next step is to check if the `hasMore` property on the launches returned is true. If true, then present a `<LoadMoreButton>` for the user to click.
165+
166+
The `<LoadMoreButton>`'s `onClick` function invokes the `fetchMore` function. By default, `fetchMore` calls the original query but with a new set of input, which is the `data.launches.cursor` value passed to the `after` key as a new variable.
167+
168+
Once the new data is returned from the server, the `updateQuery` function is used to merge it with the existing data, which will cause a re-render of your UI component with an expanded list.
169+
19170
<h2 id="testing">Test Query components</h2>

0 commit comments

Comments
 (0)