Use GraphQL Subscriptions in a React App
Subscriptions make your app respond in real time to backend data changes. This guide demonstrates how to use graphQL subscriptions in a React app.
Nov 16, 2020 • 5 Minute Read
Introduction
Modern applications are increasingly becoming real time. Some examples of real-time updates in web apps include notification updates, chat messaging applications, and financial market updates. GraphQL makes creating apps with low latency, real-time updates easy with a feature called subscriptions.
In this guide, you will learn how to subscribe to real-time updates from a GraphQL server using subscriptions. A previous guide, How to Set Up GraphQL in a React App, covered how to set up a new React Project with GraphQL using Apollo Client. This guide builds on what you learned there. Here, you will learn how to keep your client in sync with the backend by setting up a connection to allow your server to proactively push updates as they occur.
Understand How Subscriptions Are Defined in the Schema
One of the advantages of GraphQL is its strongly typed schema. This means you can see at a glance what resources are queryable and mutable. If the GraphQL backend supports it, this schema also includes information about subscriptions, which are a separate root type. If you imagined Apollo's GraphQL ExchangeRate sandbox with subscription support, then the schema would look like the snippet below:
type ExchangeRate {
currency: String
rate: String
name: String
}
type Query {
rates(currency: String!): [ExchangeRate]
}
type Subscription {
ratesUpdated(currency: String!): ExchangeRate
}
A root type called Subscription is present. This is a special optional type. It can have one or many fields. In this case, ratesUpdated is a field that clients can subscribe to by passing in a currency; every time that currency is updated on the server, a message is pushed to clients that are listening.
Enable Web Socket Support in Your React Client
To subscribe to updates, use web-sockets rather than HTTP. The IETF Standards Documentation describes the motivation for using web sockets over HTTP. The advantage of web sockets is a lower overhead transport protocol compared to HTTP. This is useful when your server has frequent small updates.
In order to support web-sockets in your React application using GraphQL, you need to install a package:
yarn add subscriptions-transport-ws
Then update your src/ApolloClient/client.js file to:
import { ApolloClient, ApolloLink, InMemoryCache, split } from "@apollo/client";
import { HttpLink } from "apollo-link-http";
import { WebSocketLink } from '@apollo/client/link/ws';
const httpLink = new HttpLink({
uri: "https://48p1r2roz4.sse.codesandbox.io",
});
const wsLink = new WebSocketLink({
uri: "ws://48p1r2roz4.sse.codesandbox.io",
options: {
reconnect: true
}
});
const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink,
);
export const client = new ApolloClient({
cache: new InMemoryCache(),
link: ApolloLink.from([splitLink]),
});
You have updated the link option, which customizes the flow of data from your graphQL operations to your backend. In this case, use the split operation to combine two links. When a mutation or query is made, then HTTP is used as the transport method. If a subscription operation is requested, you instruct ApolloClient to use web-sockets instead.
Subscribe To Updates
Now that you have the right packages and link configured correctly, you can start subscribing to data updates in your backend.
The below code snippet demonstrates a simple React component subscribing to currency rate changes.
import React from "react";
import { useQuery, gql, useSubscription } from "@apollo/client";
const RATES_UPDATED = gql`
subscription OnRatesUpdated($currency: string!) {
ratesUpdated(postID: $currency) {
currency
rate
name
}
}
`;
const LatestRates = ({ currency }) => {
const { data: { ratesUpdated }, loading } = useSubscription(
RATES_UPDATED,
{ variables: { currency } }
);
return <h4>New rates: {!loading && ratesUpdated.rate}</h4>;
};
export default LatestRates;
Notice that the code is very similar to a component with a graphQL query. There are only minor differences:
- Instead of using the useQuery hook, you used the useSubscription hook.
- The hook still returns loading, data, and error in the same way the useQuery hook does.
- The subscription also starts when the component is created for the first time.
Conclusion
Subscriptions are an extra tool that make your app respond in real time to backend data changes. This guide has demonstrated how to using graphQL subscriptions in a React app. You can further build on these skills by reading about the subscribeToMore function. This function= allows you to combine making an initial query and using a subscription to listen for incremental updates.