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:
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:
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
useSubscriptionoptiononDatais available in Apollo Client >= 3.7. In previous versions, the equivalent option is namedonSubscriptionData.
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
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
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>Parameters
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 objectuseSubscription.Result<TData>Show/hide child attributes
MaybeMasked<TData>An object containing the result of your GraphQL subscription. Defaults to an empty object.
ErrorLikeA runtime error with graphQLErrors and networkError properties
booleanA boolean that indicates whether any initial data has been returned
() => voidA 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.