UNPKG

8.23 kBMarkdownView Raw
1# react-apollo-hooks
2
3Use [Apollo Client](https://github.com/apollographql/apollo-client) as React
4[hooks](https://reactjs.org/docs/hooks-intro.html).
5
6[![CircleCI](https://circleci.com/gh/trojanowski/react-apollo-hooks.svg?style=svg)](https://circleci.com/gh/trojanowski/react-apollo-hooks)
7
8# Installation
9
10`npm install react-apollo-hooks`
11
12# Example
13
14<https://codesandbox.io/s/8819w85jn9> is a port of Pupstagram sample app to
15react-apollo-hooks.
16
17# API
18
19## ApolloProvider
20
21Similar to
22[ApolloProvider from react-apollo](https://www.apollographql.com/docs/react/essentials/get-started.html#creating-provider).
23Both packages can be used together, if you want to try out using hooks and
24retain `Query`, `Mutation`, `Subscription`, etc. HOCs from `react-apollo`
25without having to rewrite existing components throughout your app.
26
27In order for this package to work, you need to wrap your component tree with
28`ApolloProvider` at an appropriate level, encapsulating all components which
29will use hooks.
30
31### Standalone usage
32
33If you would like to use this package standalone, this can be done with:
34
35```javascript
36import React from 'react';
37import { render } from 'react-dom';
38
39import { ApolloProvider } from 'react-apollo-hooks';
40
41const client = ... // create Apollo client
42
43const App = () => (
44 <ApolloProvider client={client}>
45 <MyRootComponent />
46 </ApolloProvider>
47);
48
49render(<App />, document.getElementById('root'));
50```
51
52### Usage with react-apollo
53
54To use with `react-apollo`'s `ApolloProvider` already present in your project:
55
56```javascript
57import React from 'react';
58import { render } from 'react-dom';
59
60import { ApolloProvider } from 'react-apollo';
61import { ApolloProvider as ApolloHooksProvider } from 'react-apollo-hooks';
62
63const client = ... // create Apollo client
64
65const App = () => (
66 <ApolloProvider client={client}>
67 <ApolloHooksProvider client={client}>
68 <MyRootComponent />
69 </ApolloHooksProvider>
70 </ApolloProvider>
71);
72
73render(<App />, document.getElementById('root'));
74```
75
76## useQuery
77
78```javascript
79import gql from 'graphql-tag';
80import { useQuery } from 'react-apollo-hooks';
81
82const GET_DOGS = gql`
83 {
84 dogs {
85 id
86 breed
87 }
88 }
89`;
90
91const Dogs = () => {
92 const { data, error, loading } = useQuery(GET_DOGS);
93 if (loading) {
94 return <div>Loading...</div>;
95 };
96 if (error) {
97 return `Error! ${error.message}`;
98 };
99
100 return (
101 <ul>
102 {data.dogs.map(dog => (
103 <li key={dog.id}>{dog.breed}</li>
104 ))}
105 </ul>
106 );
107};
108
109```
110
111### Usage with Suspense (experimental)
112
113You can use `useQuery` with [React Suspense](https://www.youtube.com/watch?v=6g3g0Q_XVb4)
114with the `{ suspend: true }` option.
115Please note that it's not yet recommended to use it in production. Please look
116at the [issue #69](https://github.com/trojanowski/react-apollo-hooks/issues/69)
117for details.
118
119Example usage:
120
121```javascript
122import gql from 'graphql-tag';
123import React, { Suspense } from 'react';
124import { useQuery } from 'react-apollo-hooks';
125
126const GET_DOGS = gql`
127 {
128 dogs {
129 id
130 breed
131 }
132 }
133`;
134
135const Dogs = () => {
136 const { data, error } = useQuery(GET_DOGS, { suspend: true });
137 if (error) {
138 return `Error! ${error.message}`;
139 }
140
141 return (
142 <ul>
143 {data.dogs.map(dog => (
144 <li key={dog.id}>{dog.breed}</li>
145 ))}
146 </ul>
147 );
148};
149
150const MyComponent = () => (
151 <Suspense fallback={<div>Loading...</div>}>
152 <Dogs />
153 </Suspense>
154);
155```
156
157There are known issues with suspense mode for `useQuery`:
158
159* only the `cache-first` fetch policy is supported ([#13](https://github.com/trojanowski/react-apollo-hooks/issues/13))
160* `networkStatus` returned by `useQuery` is undefined ([#68](https://github.com/trojanowski/react-apollo-hooks/pull/68))
161
162## useMutation
163
164```javascript
165import gql from 'graphql-tag';
166import { useMutation } from 'react-apollo-hooks';
167
168const TOGGLE_LIKED_PHOTO = gql`
169 mutation toggleLikedPhoto($id: String!) {
170 toggleLikedPhoto(id: $id) @client
171 }
172`;
173
174const DogWithLikes = ({ url, imageId, isLiked }) => {
175 const toggleLike = useMutation(TOGGLE_LIKED_PHOTO, {
176 variables: { id: imageId },
177 });
178 return (
179 <div>
180 <img src={url} />
181 <button onClick={toggleLike}>{isLiked ? 'Stop liking' : 'like'}</button>
182 </div>
183 );
184};
185```
186
187You can provide any
188[mutation options](https://www.apollographql.com/docs/react/api/apollo-client.html#ApolloClient.mutate)
189as an argument to the `useMutation` hook or to the function returned by it, e.
190g.:
191
192```javascript
193function AddTaskForm() {
194 const inputRef = useRef();
195 const addTask = useMutation(ADD_TASK_MUTATION, {
196 update: (proxy, mutationResult) => {
197 /* your custom update logic */
198 },
199 variables: {
200 text: inputRef.current.value,
201 },
202 });
203
204 return (
205 <form>
206 <input ref={inputRef} />
207 <button onClick={addTask}>Add task</button>
208 </form>
209 );
210}
211```
212
213Or:
214
215```javascript
216function TasksWithMutation() {
217 const toggleTask = useMutation(TOGGLE_TASK_MUTATION);
218
219 return (
220 <TaskList
221 onChange={task => toggleTask({ variables: { taskId: task.id } })}
222 tasks={data.tasks}
223 />
224 );
225}
226```
227
228## useSubscription
229
230If you are just interested in the last subscription value sent by the
231server (e. g. a global indicator showing how many new messages you have in an
232instant messenger app) you can use `useSubscription` hook in this form:
233
234```javascript
235const NEW_MESSAGES_COUNT_CHANGED_SUBSCRIPTION = gql`
236 subscription onNewMessagesCountChanged($repoFullName: String!) {
237 newMessagesCount
238 }
239`;
240
241const NewMessagesIndicator = () => {
242 const { data, error, loading } = useSubscription(
243 NEW_MESSAGES_COUNT_CHANGED_SUBSCRIPTION
244 );
245
246 if (loading) {
247 return <div>Loading...</div>;
248 };
249
250 if (error) {
251 return <div>Error! {error.message}`</div>;
252 };
253
254 return <div>{data.newMessagesCount} new messages</div>;
255}
256```
257
258For more advanced use cases, e. g. when you'd like to show a notification
259to the user or modify the Apollo cache (e. g. you'd like to show a new comment
260on a blog post page for a user visiting it just after it was created) you can
261use the `onSubscriptionData` callback:
262
263```javascript
264const { data, error, loading } = useSubscription(MY_SUBSCRIPTION, {
265 variables: {
266 // ...
267 },
268 onSubscriptionData: ({ client, subscriptionData }) => {
269 // Optional callback which provides you access to the new subscription
270 // data and the Apollo client. You can use methods of the client to update
271 // the Apollo cache:
272 // https://www.apollographql.com/docs/react/advanced/caching.html#direct
273 }
274 // ... rest options
275});
276```
277
278
279## useApolloClient
280
281```javascript
282const MyComponent = () => {
283 const client = useApolloClient();
284 // now you have access to the Apollo client
285};
286```
287
288# Testing
289
290An example showing how to test components using react-apollo-hooks:
291<https://github.com/trojanowski/react-apollo-hooks-sample-test>
292
293# Server-side rendering
294
295react-apollo-hooks supports server-side rendering with the `getMarkupFromTree`
296function. Example usage:
297
298```javascript
299import express from 'express';
300import { ApolloProvider, getMarkupFromTree } from 'react-apollo-hooks';
301import { renderToString } from 'react-dom/server';
302
303const HELLO_QUERY = gql`
304 query HelloQuery {
305 hello
306 }
307`;
308
309function Hello() {
310 const { data } = useQuery(HELLO_QUERY);
311
312 return <p>{data.message}</p>;
313}
314
315const app = express();
316
317app.get('/', async (req, res) => {
318 const client = createYourApolloClient();
319 const renderedHtml = await getMarkupFromTree({
320 renderFunction: renderToString,
321 tree: (
322 <ApolloProvider client={client}>
323 <Hello />
324 </ApolloProvider>
325 ),
326 });
327 res.send(renderedHtml);
328});
329```
330
331`getMarkupFromTree` supports `useQuery` hooks invoked in both suspense
332and non-suspense mode, but the [React.Suspense](https://reactjs.org/docs/react-api.html#reactsuspense)
333component is not supported. You can use `unstable_SuspenseSSR` provided
334by this library instead:
335
336```javascript
337import { unstable_SuspenseSSR as UnstableSuspenseSSR } from 'react-apollo-hooks';
338
339function MyComponent() {
340 return (
341 <UnstableSuspenseSSR fallback={<Spinner />}>
342 <div>
343 <ComponentWithGraphqlQuery />
344 </div>
345 </UnstableSuspenseSSR>
346 );
347}
348```