1---
2title: React/Preact Bindings
3order: 0
4---
5
6# React/Preact
7
8This guide covers how to install and setup `urql` and the `Client`, as well as query and mutate data,
9with React and Preact. Since the `urql` and `@urql/preact` packages share most of their API and are
10used in the same way, when reading the documentation on React, all examples are essentially the same,
11except that we'd want to use the `@urql/preact` package instead of the `urql` package.
12
13## Getting started
14
15### Installation
16
17Installing `urql` is as quick as you'd expect, and you won't need any other packages to get started
18with at first. We'll install the package with our package manager of choice.
19
20```sh
21yarn add urql
22# or
23npm install --save urql
24```
25
26To use `urql` with Preact, we have to install `@urql/preact` instead of `urql` and import from
27that package instead. Otherwise all examples for Preact will be the same.
28
29Most libraries related to GraphQL also need the `graphql` package to be installed as a peer
30dependency, so that they can adapt to your specific versioning requirements. That's why we'll need
31to install `graphql` alongside `urql`.
32
33Both the `urql` and `graphql` packages follow [semantic versioning](https://semver.org) and all
34`urql` packages will define a range of compatible versions of `graphql`. Watch out for breaking
35changes in the future however, in which case your package manager may warn you about `graphql` being
36out of the defined peer dependency range.
37
38### Setting up the `Client`
39
40The `urql` and `@urql/preact` packages export a `Client` class, which we can use to
41create the GraphQL client. This central `Client` manages all of our GraphQL requests and results.
42
43```js
44import { Client, cacheExchange, fetchExchange } from 'urql';
45
46const client = new Client({
47 url: 'http://localhost:3000/graphql',
48 exchanges: [cacheExchange, fetchExchange],
49});
50```
51
52At the bare minimum we'll need to pass an API's `url` and `exchanges` when we create a `Client`
53to get started.
54
55Another common option is `fetchOptions`. This option allows us to customize the options that will be
56passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object, or
57a function returning an options object.
58
59In the following example we'll add a token to each `fetch` request that our `Client` sends to our
60GraphQL API.
61
62```js
63const client = new Client({
64 url: 'http://localhost:3000/graphql',
65 exchanges: [cacheExchange, fetchExchange],
66 fetchOptions: () => {
67 const token = getToken();
68 return {
69 headers: { authorization: token ? `Bearer ${token}` : '' },
70 };
71 },
72});
73```
74
75### Providing the `Client`
76
77To make use of the `Client` in React & Preact we will have to provide it via the
78[Context API](https://reactjs.org/docs/context.html). This may be done with the help of
79the `Provider` export.
80
81```jsx
82import { Client, Provider, cacheExchange, fetchExchange } from 'urql';
83
84const client = new Client({
85 url: 'http://localhost:3000/graphql',
86 exchanges: [cacheExchange, fetchExchange],
87});
88
89const App = () => (
90 <Provider value={client}>
91 <YourRoutes />
92 </Provider>
93);
94```
95
96Now every component and element inside and under the `Provider` can use GraphQL queries that
97will be sent to our API.
98
99## Queries
100
101Both libraries offer a `useQuery` hook and a `Query` component. The latter accepts the same
102parameters, but we won't cover it in this guide. [Look it up in the API docs if you prefer
103render-props components.](../api/urql.md#query-component)
104
105### Run a first query
106
107For the following examples, we'll imagine that we're querying data from a GraphQL API that contains
108todo items. Let's dive right into it!
109
110```jsx
111import { gql, useQuery } from 'urql';
112
113const TodosQuery = gql`
114 query {
115 todos {
116 id
117 title
118 }
119 }
120`;
121
122const Todos = () => {
123 const [result, reexecuteQuery] = useQuery({
124 query: TodosQuery,
125 });
126
127 const { data, fetching, error } = result;
128
129 if (fetching) return <p>Loading...</p>;
130 if (error) return <p>Oh no... {error.message}</p>;
131
132 return (
133 <ul>
134 {data.todos.map(todo => (
135 <li key={todo.id}>{todo.title}</li>
136 ))}
137 </ul>
138 );
139};
140```
141
142Here we have implemented our first GraphQL query to fetch todos. We see that `useQuery` accepts
143options and returns a tuple. In this case we've set the `query` option to our GraphQL query. The
144tuple we then get in return is an array that contains a result object, and a re-execute function.
145
146The result object contains several properties. The `fetching` field indicates whether the hook is
147loading data, `data` contains the actual `data` from the API's result, and `error` is set when either
148the request to the API has failed or when our API result contained some `GraphQLError`s, which
149we'll get into later on the ["Errors" page](./errors.md).
150
151### Variables
152
153Typically we'll also need to pass variables to our queries, for instance, if we are dealing with
154pagination. For this purpose the `useQuery` hook also accepts a `variables` option, which we can use
155to supply variables to our query.
156
157```jsx
158const TodosListQuery = gql`
159 query ($from: Int!, $limit: Int!) {
160 todos(from: $from, limit: $limit) {
161 id
162 title
163 }
164 }
165`;
166
167const Todos = ({ from, limit }) => {
168 const [result, reexecuteQuery] = useQuery({
169 query: TodosListQuery,
170 variables: { from, limit },
171 });
172
173 // ...
174};
175```
176
177As when we're sending GraphQL queries manually using `fetch`, the variables will be attached to the
178`POST` request body that is sent to our GraphQL API.
179
180Whenever the `variables` (or the `query`) option on the `useQuery` hook changes `fetching` will
181switch to `true`, and a new request will be sent to our API, unless a result has already been cached
182previously.
183
184### Pausing `useQuery`
185
186In some cases we may want `useQuery` to execute a query when a pre-condition has been met, and not
187execute the query otherwise. For instance, we may be building a form and want a validation query to
188only take place when a field has been filled out.
189
190Since hooks in React can't just be commented out, the `useQuery` hook accepts a `pause` option that
191temporarily _freezes_ all changes and stops requests.
192
193In the previous example we've defined a query with mandatory arguments. The `$from` and `$limit`
194variables have been defined to be non-nullable `Int!` values.
195
196Let's pause the query we've just
197written to not execute when these variables are empty, to prevent `null` variables from being
198executed. We can do this by setting the `pause` option to `true`:
199
200```jsx
201const Todos = ({ from, limit }) => {
202 const shouldPause = from === undefined || from === null || limit === undefined || limit === null;
203 const [result, reexecuteQuery] = useQuery({
204 query: TodosListQuery,
205 variables: { from, limit },
206 pause: shouldPause,
207 });
208
209 // ...
210};
211```
212
213Now whenever the mandatory `$from` or `$limit` variables aren't supplied the query won't be executed.
214This also means that `result.data` won't change, which means we'll still have access to our old data
215even though the variables may have changed.
216
217### Request Policies
218
219As has become clear in the previous sections of this page, the `useQuery` hook accepts more options
220than just `query` and `variables`. Another option we should touch on is `requestPolicy`.
221
222The `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By
223default, this is set to `cache-first`, which means that we prefer to get results from our cache, but
224are falling back to sending an API request.
225
226Request policies aren't specific to `urql`'s React API, but are a common feature in its core. [You
227can learn more about how the cache behaves given the four different policies on the "Document
228Caching" page.](../basics/document-caching.md)
229
230```jsx
231const [result, reexecuteQuery] = useQuery({
232 query: TodosListQuery,
233 variables: { from, limit },
234 requestPolicy: 'cache-and-network',
235});
236```
237
238Specifically, a new request policy may be passed directly to the `useQuery` hook as an option.
239This policy is then used for this specific query. In this case, `cache-and-network` is used and
240the query will be refreshed from our API even after our cache has given us a cached result.
241
242Internally, the `requestPolicy` is just one of several "**context** options". The `context`
243provides metadata apart from the usual `query` and `variables` we may pass. This means that
244we may also change the `Client`'s default `requestPolicy` by passing it there.
245
246```js
247import { Client, cacheExchange, fetchExchange } from 'urql';
248
249const client = new Client({
250 url: 'http://localhost:3000/graphql',
251 exchanges: [cacheExchange, fetchExchange],
252 // every operation will by default use cache-and-network rather
253 // than cache-first now:
254 requestPolicy: 'cache-and-network',
255});
256```
257
258### Context Options
259
260As mentioned, the `requestPolicy` option on `useQuery` is a part of `urql`'s context options.
261In fact, there are several more built-in context options, and the `requestPolicy` option is
262one of them. Another option we've already seen is the `url` option, which determines our
263API's URL. These options aren't limited to the `Client` and may also be passed per query.
264
265```jsx
266import { useMemo } from 'react';
267import { useQuery } from 'urql';
268
269const Todos = ({ from, limit }) => {
270 const [result, reexecuteQuery] = useQuery({
271 query: TodosListQuery,
272 variables: { from, limit },
273 context: useMemo(
274 () => ({
275 requestPolicy: 'cache-and-network',
276 url: 'http://localhost:3000/graphql?debug=true',
277 }),
278 []
279 ),
280 });
281
282 // ...
283};
284```
285
286As we can see, the `context` property for `useQuery` accepts any known `context` option and can be
287used to alter them per query rather than globally. The `Client` accepts a subset of `context`
288options, while the `useQuery` option does the same for a single query.
289[You can find a list of all `Context` options in the API docs.](../api/core.md#operationcontext)
290
291### Reexecuting Queries
292
293The `useQuery` hook updates and executes queries whenever its inputs, like the `query` or
294`variables` change, but in some cases we may find that we need to programmatically trigger a new
295query. This is the purpose of the `reexecuteQuery` function, which is the second item in the tuple
296that `useQuery` returns.
297
298Triggering a query programmatically may be useful in a couple of cases. It can for instance be used
299to refresh the hook's data. In these cases we may also override the `requestPolicy` of our query just
300once and set it to `network-only` to skip the cache.
301
302```jsx
303const Todos = ({ from, limit }) => {
304 const [result, reexecuteQuery] = useQuery({
305 query: TodosListQuery,
306 variables: { from, limit },
307 });
308
309 const refresh = () => {
310 // Refetch the query and skip the cache
311 reexecuteQuery({ requestPolicy: 'network-only' });
312 };
313};
314```
315
316Calling `refresh` in the above example will execute the query again forcefully, and will skip the
317cache, since we're passing `requestPolicy: 'network-only'`.
318
319Furthermore the `reexecuteQuery` function can also be used to programmatically start a query even
320when `pause` is set to `true`, which would usually stop all automatic queries. This can be used to
321perform one-off actions, or to set up polling.
322
323```jsx
324import { useEffect } from 'react';
325import { useQuery } from 'urql';
326
327const Todos = ({ from, limit }) => {
328 const [result, reexecuteQuery] = useQuery({
329 query: TodosListQuery,
330 variables: { from, limit },
331 pause: true,
332 });
333
334 useEffect(() => {
335 if (result.fetching) return;
336
337 // Set up to refetch in one second, if the query is idle
338 const timerId = setTimeout(() => {
339 reexecuteQuery({ requestPolicy: 'network-only' });
340 }, 1000);
341
342 return () => clearTimeout(timerId);
343 }, [result.fetching, reexecuteQuery]);
344
345 // ...
346};
347```
348
349There are some more tricks we can use with `useQuery`. [Read more about its API in the API docs for
350it.](../api/urql.md#usequery)
351
352## Mutations
353
354Both libraries offer a `useMutation` hook and a `Mutation` component. The latter accepts the same
355parameters, but we won't cover it in this guide. [Look it up in the API docs if you prefer
356render-props components.](../api/urql.md#mutation-component)
357
358### Sending a mutation
359
360Let's again pick up an example with an imaginary GraphQL API for todo items, and dive into an
361example! We'll set up a mutation that _updates_ a todo item's title.
362
363```jsx
364const UpdateTodo = `
365 mutation ($id: ID!, $title: String!) {
366 updateTodo (id: $id, title: $title) {
367 id
368 title
369 }
370 }
371`;
372
373const Todo = ({ id, title }) => {
374 const [updateTodoResult, updateTodo] = useMutation(UpdateTodo);
375};
376```
377
378Similar to the `useQuery` output, `useMutation` returns a tuple. The first item in the tuple again
379contains `fetching`, `error`, and `data` — it's identical since this is a common pattern of how
380`urql` presents [operation results](../api/core.md#operationresult).
381
382Unlike the `useQuery` hook, the `useMutation` hook doesn't execute automatically. At this point in
383our example, no mutation will be performed. To execute our mutation we instead have to call the
384execute function — `updateTodo` in our example — which is the second item in the tuple.
385
386### Using the mutation result
387
388When calling our `updateTodo` function we have two ways of getting to the result as it comes back
389from our API. We can either use the first value of the returned tuple, our `updateTodoResult`, or
390we can use the promise that `updateTodo` returns.
391
392```jsx
393const Todo = ({ id, title }) => {
394 const [updateTodoResult, updateTodo] = useMutation(UpdateTodo);
395
396 const submit = newTitle => {
397 const variables = { id, title: newTitle || '' };
398 updateTodo(variables).then(result => {
399 // The result is almost identical to `updateTodoResult` with the exception
400 // of `result.fetching` not being set.
401 // It is an OperationResult.
402 });
403 };
404};
405```
406
407The result is useful when your UI has to display progress on the mutation, and the returned
408promise is particularly useful when you're adding side effects that run after the mutation has
409completed.
410
411### Handling mutation errors
412
413It's worth noting that the promise we receive when calling the execute function will never
414reject. Instead it will always return a promise that resolves to a result.
415
416If you're checking for errors, you should use `result.error` instead, which will be set
417to a `CombinedError` when any kind of errors occurred while executing your mutation.
418[Read more about errors on our "Errors" page.](./errors.md)
419
420```jsx
421const Todo = ({ id, title }) => {
422 const [updateTodoResult, updateTodo] = useMutation(UpdateTodo);
423
424 const submit = newTitle => {
425 const variables = { id, title: newTitle || '' };
426 updateTodo(variables).then(result => {
427 if (result.error) {
428 console.error('Oh no!', result.error);
429 }
430 });
431 };
432};
433```
434
435There are some more tricks we can use with `useMutation`.<br />
436[Read more about its API in the API docs for it.](../api/urql.md#usemutation)
437
438## Reading on
439
440This concludes the introduction for using `urql` with React or Preact. The rest of the documentation
441is mostly framework-agnostic and will apply to either `urql` in general, or the `@urql/core` package,
442which is the same between all framework bindings. Hence, next we may want to learn more about one of
443the following to learn more about the internals:
444
445- [How does the default "document cache" work?](./document-caching.md)
446- [How are errors handled and represented?](./errors.md)
447- [A quick overview of `urql`'s architecture and structure.](../architecture.md)
448- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)