Working with URQL, React and GraphQL Live Queries

Working with URQL, React and GraphQL Live Queries

URQL is great for executing GraphQL operations and managing local state. But when data changes on the server (by other users), there's no way to know that happened without refetching the query.

Polling often bloats the network, and overfetches data you already know about. Instead you can use GraphQL Live Queries to keep the client updated.

URQL ships with a highly configurable exchange pipeline that we can add a custom exchange for working with Live Queries.

In this guide we will use the @grafbase/urql-exchange library to switch connection types depending on the type of query invoked.

npm install urql graphql @grafbase/urql-exchange

We'll begin by invoking createClient from urql to initialize a new client:

import { cacheExchange, createClient, dedupExchange, fetchExchange } from 'urql'

// Token generated by your auth provider: https://grafbase.com/docs/reference/directives#auth
const token = '....'

export const client = createClient({
  url: process.env.GRAFBASE_API_URL,
  fetchOptions: {
    headers: {
      authorization: `Bearer ${token}`
    }
  },
  exchanges: [dedupExchange, cacheExchange, fetchExchange]
})

Note: It's here you will also use an auth provider to set the token value.

Next import and add sseExchange from @grafbase/urql-exchange to your list of exchanges. Make sure to add sseExchange before fetchExchange.

import { sseExchange } from '@grafbase/url-exchange'
import { cacheExchange, createClient, dedupExchange, fetchExchange } from 'urql'

// Token generated by your auth provider: https://grafbase.com/docs/reference/directives#auth
const token = '....'

export const client = createClient({
  url: process.env.GRAFBASE_API_URL,
  fetchOptions: {
    headers: {
      authorization: `Bearer ${token}`
    }
  },
  exchanges: [dedupExchange, cacheExchange, sseExchange, fetchExchange]
})

Now you will need to import Provider from urql, wrap your application and pass the custom client instance as the provider value:

import React from 'react'
import ReactDOM from 'react-dom/client'
import {
  Provider,
  cacheExchange,
  createClient,
  dedupExchange,
  fetchExchange
} from 'urql'

const App = () => {
  return (
    // ...
  )
}

ReactDOM.createRoot(document.getElementById('root')).render(
  <Provider value={client}>
    <App />
  </Provider>
)

You can now use the @live directive with any query and URQL will automatically listen for changes using server-sent events.

query @live {
  messageCollection(first: 5) {
    edges {
      node {
        id
        body
      }
    }
  }
}

That's it! URQL will now automatically use the necessary exchange when executing queries.