Create Subscription and Render Result
So let's define the graphql subscription to be used.
Open src/components/OnlineUsers/OnlineUsersWrapper.tsx
and add the following code, below the other imports
import React, { useEffect } from "react";import gql from "graphql-tag";- import { gql, useMutation } from "@apollo/client";+ import { gql, useMutation, useSubscription } from "@apollo/client";import OnlineUser from "./OnlineUser";const UPDATE_LASTSEEN_MUTATION=gql`mutation updateLastSeen ($now: timestamptz!) {update_users(where: {}, _set: {last_seen: $now}) {affected_rows}}`;+ const GET_ONLINE_USERS = gql`+ subscription getOnlineUsers {+ online_users(order_by: {user: {name: asc }}) {+ id+ user {+ name+ }+ }+ }+ `;
We are importing the useSubscription
hook from @apollo/react-hooks
and the graphql subscription query is defined above to fetch the online user data.
Now, we will pass the subscription constant to useSubscription
hook.
const OnlineUsersWrapper = () => {const [updateLastSeen] = useMutation(UPDATE_LASTSEEN_MUTATION);+ const { data, loading, error } = useSubscription(GET_ONLINE_USERS);
Now that we have the real data, let's remove the mock online user state and handle loading/error states.
const OnlineUsersWrapper = () => {const [updateLastSeen] = useMutation(UPDATE_LASTSEEN_MUTATION);const { data, loading, error } = useSubscription(GET_ONLINE_USERS);useEffect(() => {const onlineIndicator = setInterval(() => updateLastSeen({variables: { now: (new Date()).toISOString()}}), 20000);return () => clearInterval(onlineIndicator);});+ if(loading) {+ return (<div>Loading...</div>);+ }+ if(error || !data) {+ return(<div>Error...</div>);+ }- const online_users = [- { name: "someUser1" },- { name: "someUser2" }- ];- const onlineUsersList = online_users.map((user, index) => (+ const onlineUsersList = data.online_users.map((user:any, index:number) => (<OnlineUser- user={user}+ user={user.user}key={index}/>));return (<div className="onlineUsersWrapper"><div className="sliderHeader">- Online users - {online_users.length}+ Online users - {data.online_users.length}</div>{ onlineUsersList }</div>);}
How does this work?
We are using the useSubscription
hook which gives a result object. The data
key gives the result of the realtime data for the query we have made.
Refresh your react app and see yourself online! Don't be surprised; There could be other users online as well.
Mapping Types
We need type definitions for the mutation and subscription requests made in this component.
For the mutation, we need the type definitions for UpdateLastSeenMutation
and for the subscriptions, we need the type definitions for GetOnlineUsersSubscription
.
import React, { useEffect } from "react";import gql from "graphql-tag";import { useMutation, useSubscription } from "@apollo/react-hooks";+ import { UpdateLastSeenMutation, GetOnlineUsersSubscription } from '../../generated/graphql';
Let's apply this to the hooks.
const OnlineUsersWrapper = () => {- const [updateLastSeen] = useMutation(UPDATE_LASTSEEN_MUTATION);+ const [updateLastSeen] = useMutation<UpdateLastSeenMutation>(UPDATE_LASTSEEN_MUTATION);- const { data, loading, error } = useSubscription(GET_ONLINE_USERS);+ const { data, loading, error } = useSubscription<GetOnlineUsersSubscription>(GET_ONLINE_USERS);
Finally, we will remove the explicit usage of any
by importing the types of Online_Users
in both OnlineUsersWrapper.tsx
and OnlineUser.tsx
files.
- import { UpdateLastSeenMutation, GetOnlineUsersSubscription } from '../../generated/graphql';+ import { UpdateLastSeenMutation, GetOnlineUsersSubscription, Online_Users } from '../../generated/graphql';......- const onlineUsersList = data.online_users.map((user:any, index:number) => (+ const onlineUsersList = data.online_users.map((user:Online_Users, index:number) => (<OnlineUseruser={user.user}key={index}/>));
And now open src/components/OnlineUsers/OnlineUser.tsx
import * as React from 'react';+ import { Online_Users } from '../../generated/graphql';- type user = {- name: string;- }- const OnlineUser = ({user}:{user: user}) => {+ const OnlineUser = ({user}: Online_Users) => {return (<div className="userInfo"><div className="userImg"><i className="far fa-user" /></div><div className="userName">{user ? user.name : null}</div></div>);};export default OnlineUser;
Awesome! You have completed implementations of a GraphQL Query, Mutation and Subscriptions.
- Build apps and APIs 10x faster
- Built-in authorization and caching
- 8x more performant than hand-rolled APIs