Handle real-time GraphQL subscriptions for live data updates.
Subscribe to GraphQL subscriptions for real-time data updates and live UI synchronization.
/**
* Subscribe to GraphQL subscriptions for real-time data updates
* @param subscription - GraphQL subscription document
* @param options - Configuration options for the subscription
* @returns Subscription result with data, loading, and error states
*/
function useSubscription<TData = any, TVariables = OperationVariables>(
subscription: DocumentNode,
options?: SubscriptionHookOptions<TData, TVariables>
): SubscriptionResult<TData>;
interface SubscriptionHookOptions<TData, TVariables> {
/** Variables to pass to the subscription */
variables?: TVariables;
/** Skip executing the subscription */
skip?: boolean;
/** Fetch policy for subscription */
fetchPolicy?: FetchPolicy;
/** Error policy for handling GraphQL errors */
errorPolicy?: ErrorPolicy;
/** Context passed to Apollo Link */
context?: DefaultContext;
/** Client instance to use */
client?: ApolloClient<any>;
/** Callback when subscription data arrives */
onData?: (options: OnDataOptions<TData>) => void;
/** Callback when subscription completes */
onComplete?: () => void;
/** Callback when subscription errors */
onError?: (error: ApolloError) => void;
/** Whether to ignore results */
ignoreResults?: boolean;
/** Whether the subscription should re-subscribe */
shouldResubscribe?: boolean | ((options: BaseSubscriptionOptions<TData, TVariables>) => boolean);
}
interface SubscriptionResult<TData> {
/** Subscription data */
data?: TData;
/** Loading state */
loading: boolean;
/** Error state */
error?: ApolloError;
}
interface OnDataOptions<TData> {
/** Apollo Client instance */
client: ApolloClient<object>;
/** Subscription data */
data: SubscriptionResult<TData>;
}Usage Examples:
import { useSubscription, gql } from "@apollo/react-hooks";
const MESSAGE_SUBSCRIPTION = gql`
subscription OnMessageAdded($chatId: ID!) {
messageAdded(chatId: $chatId) {
id
content
user {
id
name
}
createdAt
}
}
`;
function ChatMessages({ chatId }: { chatId: string }) {
const { data, loading, error } = useSubscription(MESSAGE_SUBSCRIPTION, {
variables: { chatId },
onData: ({ data }) => {
console.log("New message received:", data.data?.messageAdded);
},
onError: (error) => {
console.error("Subscription error:", error);
},
});
if (loading) return <div>Connecting to chat...</div>;
if (error) return <div>Connection error: {error.message}</div>;
return (
<div>
{data?.messageAdded && (
<div className="new-message">
<strong>{data.messageAdded.user.name}:</strong>
{data.messageAdded.content}
</div>
)}
</div>
);
}Advanced Usage with Cache Updates:
import { useSubscription, useQuery, gql } from "@apollo/react-hooks";
const GET_MESSAGES = gql`
query GetMessages($chatId: ID!) {
messages(chatId: $chatId) {
id
content
user {
id
name
}
createdAt
}
}
`;
const MESSAGE_SUBSCRIPTION = gql`
subscription OnMessageAdded($chatId: ID!) {
messageAdded(chatId: $chatId) {
id
content
user {
id
name
}
createdAt
}
}
`;
function ChatRoom({ chatId }: { chatId: string }) {
// Query existing messages
const { data: messagesData, loading } = useQuery(GET_MESSAGES, {
variables: { chatId },
});
// Subscribe to new messages
useSubscription(MESSAGE_SUBSCRIPTION, {
variables: { chatId },
onData: ({ client, data }) => {
if (data.data?.messageAdded) {
// Update cache with new message
client.cache.modify({
fields: {
messages(existingMessages = [], { readField }) {
const newMessage = data.data.messageAdded;
// Avoid duplicates
const exists = existingMessages.some((msgRef: any) =>
readField('id', msgRef) === newMessage.id
);
if (!exists) {
const newMessageRef = client.cache.writeFragment({
data: newMessage,
fragment: gql`
fragment NewMessage on Message {
id
content
user {
id
name
}
createdAt
}
`,
});
return [...existingMessages, newMessageRef];
}
return existingMessages;
},
},
});
}
},
});
if (loading) return <div>Loading messages...</div>;
return (
<div className="chat-room">
<div className="messages">
{messagesData?.messages.map((message: any) => (
<div key={message.id} className="message">
<strong>{message.user.name}:</strong>
<span>{message.content}</span>
<small>{new Date(message.createdAt).toLocaleTimeString()}</small>
</div>
))}
</div>
</div>
);
}Conditional Subscriptions:
import { useSubscription, gql } from "@apollo/react-hooks";
const USER_STATUS_SUBSCRIPTION = gql`
subscription OnUserStatusChanged($userId: ID!) {
userStatusChanged(userId: $userId) {
id
status
lastSeen
}
}
`;
function UserStatus({ userId, isOnline }: { userId: string; isOnline: boolean }) {
const { data, error } = useSubscription(USER_STATUS_SUBSCRIPTION, {
variables: { userId },
// Only subscribe when user is online
skip: !isOnline,
shouldResubscribe: (options) => {
// Re-subscribe when variables change
return options.variables?.userId !== userId;
},
});
if (error) {
return <div>Status unavailable</div>;
}
const status = data?.userStatusChanged?.status || 'unknown';
return (
<div className={`user-status ${status}`}>
Status: {status}
</div>
);
}interface BaseSubscriptionOptions<TData, TVariables> {
variables?: TVariables;
fetchPolicy?: FetchPolicy;
errorPolicy?: ErrorPolicy;
context?: DefaultContext;
}
type FetchPolicy =
| 'cache-first'
| 'cache-only'
| 'cache-and-network'
| 'network-only'
| 'no-cache'
| 'standby';
type ErrorPolicy = 'none' | 'ignore' | 'all';