useSubscription

Apollo Client API reference


Refer to the Subscriptions section for a more in-depth overview of useSubscription.

Consider using onData instead of useEffect

If you want to react to incoming data, please use the onData option instead of useEffect. State updates you make inside a useEffect hook might cause additional rerenders, and useEffect is mostly meant for side effects of rendering, not as an event handler. State updates made in an event handler like onData might - depending on the React version - be batched and cause only a single rerender.

Consider the following component:

JavaScript
1export function Subscriptions() {
2  const { data, error, loading } = useSubscription(query);
3  const [accumulatedData, setAccumulatedData] = useState([]);
4
5  useEffect(() => {
6    setAccumulatedData((prev) => [...prev, data]);
7  }, [data]);
8
9  return (
10    <>
11      {loading && <p>Loading...</p>}
12      {JSON.stringify(accumulatedData, undefined, 2)}
13    </>
14  );
15}

Instead of using useEffect here, we can re-write this component to use the onData callback function accepted in useSubscription's options object:

JavaScript
1export function Subscriptions() {
2  const [accumulatedData, setAccumulatedData] = useState([]);
3  const { data, error, loading } = useSubscription(query, {
4    onData({ data }) {
5      setAccumulatedData((prev) => [...prev, data]);
6    },
7  });
8
9  return (
10    <>
11      {loading && <p>Loading...</p>}
12      {JSON.stringify(accumulatedData, undefined, 2)}
13    </>
14  );
15}

⚠️ Note: The useSubscription option onData is available in Apollo Client >= 3.7. In previous versions, the equivalent option is named onSubscriptionData.

Now, the first message will be added to the accumulatedData array since onData is called before the component re-renders. React 18 automatic batching is still in effect and results in a single re-render, but with onData we can guarantee each message received after the component mounts is added to accumulatedData.

Example

JavaScript
1 const COMMENTS_SUBSCRIPTION = gql`
2   subscription OnCommentAdded($repoFullName: String!) {
3     commentAdded(repoFullName: $repoFullName) {
4       id
5       content
6     }
7   }
8 `;
9
10 function DontReadTheComments({ repoFullName }) {
11   const {
12     data: { commentAdded },
13     loading,
14   } = useSubscription(COMMENTS_SUBSCRIPTION, { variables: { repoFullName } });
15   return <h4>New comment: {!loading && commentAdded.content}</h4>;
16 }

Signature

TypeScript
1useSubscription<TData, TVariables>(
2  subscription: DocumentNode | TypedDocumentNode<TData, TVariables>,
3  [options]: {} extends (TVariables) ? [
4    options?: useSubscription.Options<NoInfer<TData>, NoInfer<TVariables>>
5] : [options: useSubscription.Options<NoInfer<TData>, NoInfer<TVariables>>]
6): useSubscription.Result<TData>
(src/react/hooks/useSubscription.ts)

Parameters

Name / Type
Description
subscription
DocumentNode | TypedDocumentNode<TData, TVariables>

A GraphQL subscription document parsed into an AST by gql.

[options]
{} extends (TVariables) ? [ options?: useSubscription.Options<NoInfer<TData>, NoInfer<TVariables>> ] : [options: useSubscription.Options<NoInfer<TData>, NoInfer<TVariables>>]

Result

Query result object
useSubscription.Result<TData>
Show/hide child attributes
MaybeMasked<TData>

An object containing the result of your GraphQL subscription. Defaults to an empty object.

A runtime error with graphQLErrors and networkError properties

boolean

A boolean that indicates whether any initial data has been returned

() => void

A function that when called will disconnect and reconnect the connection to the subscription. If the subscription is deduplicated, this will restart the connection for all deduplicated subscriptions.

Feedback

Edit on GitHub

Ask Community