React with Graphql Subscriptions
Author : JaNakh Pon , September 12, 2021
Tags
GraphQL Subscriptions
Subscriptions allow clients to listen to real-time messages from the server. The client connects to the server with a bi-directional communication channel using the WebSocket protocol and sends a subscription query that specifies which event it is interested in. When an event is triggered, the server executes the stored GraphQL query, and the result is sent back to the client using the same communication channel.
The client can unsubscribe by sending a message to the server. The server can also unsubscribe at any time due to errors or timeouts. A significant difference between queries or mutations and subscriptions is that subscriptions are stateful and require maintaining the GraphQL document, variables, and context over the lifetime of the subscription.
Summary
In this article, we are going to add graphql-subscriptions
to our react app to be able to get realtime data updates from our backend api
.
To be able to use subscription in react app, we will need to install a few dependencies and set up WebSocket url for ApolloClient .
At first, we will use pollInterval to fetch updates from the backend every x seconds. However, pollInterval
will not get us the realtime data so we will use useSubscription to do just that!.
Installation & Setup
Firstly, let's install the subscriptions-transport-ws
dependency 😉:
> npm i subscriptions-transport-ws --save
And let's update our Apollo Client config file under /utils/
:
import { ApolloClient, InMemoryCache, HttpLink, split } from '@apollo/client'
import { getMainDefinition } from '@apollo/client/utilities';
import { WebSocketLink } from '@apollo/client/link/ws';
import authLink from './authlink'
const httpLink = new HttpLink({
uri: 'http://localhost:3001/graphql',
});
const wsLink = new WebSocketLink({
uri: 'ws://localhost:3001/graphql',
options: {
reconnect: true,
},
});
const link = split(({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition'
&& definition.operation === 'subscription'
);
}, wsLink, authLink.concat(httpLink));
const client = new ApolloClient({
link: link,
cache: new InMemoryCache({
addTypename: false
}),
defaultOptions: {
watchQuery: {
fetchPolicy: 'no-cache'
}
}
});
export default client;
Defining methods for subscriptions
Just like methods for query and mutation that we defined in the previous article, we should be able to copy our subscription methods from our graphql playground and wrap it around "gql" tag.
> cd graphql && touch subCreate.tsx subDelete.tsx subUpdate.tsx && cd ..
For example:
import gql from 'graphql-tag'
export default gql`
subscription notifyCreation {
todoCreated{
id
title
text
completed
}
}
`
Implementation
In this step, we are going to add pollInterval to our useQuery
first to fetch updated data on every 0.5 second
and then we will use useSubscription
to get realtime data.
pollInterval example:
const { data: list_data, refetch: refetchList } = useQuery(GQL_GETLIST, {
fetchPolicy: 'network-only',
variables: { page, take: 5, sort, order },
pollInterval: 500 // every 0.5 second
})
And 'useSubscription' to refetch data on every create/update/delete mutation
:
const { data: sub_create_data } = useSubscription(GQL_SUBCREATE)
const { data: sub_update_data } = useSubscription(GQL_SUBUPDATE)
const { data: sub_delete_data } = useSubscription(GQL_SUBDELETE)
useEffect(() => {
if (sub_create_data || sub_update_data || sub_delete_data) {
refetchList()
}
}, [sub_create_data, sub_update_data, sub_delete_data, refetchList])
Everything should be working by now. So, you should be able to see it in action by opening two browser windows for http://localhost:3000 and try to create/update/delete task on one window and monitor the changes on the the other window!.