Search code examples
reactjsapollo-clientreact-apollo

The react apollo useSubscription hook doesn't work in a function call but works when the same call is assigned to a variable


I am working with apollo graphql client. The subscription in the server is working fine watching for changes.

But in the client, I am not able to log data. I also tried to mutate but still its resulting in the same thing.

useSubscription(BOOK_ADDED, {
    onData: ({ data }) => {
      console.log(data)
    }
  })

The above code doesn't log anything out.

But,

const value = useSubscription(BOOK_ADDED, {
  onData: ({ data }) => {
      console.log(data)
    }
  })
 console.log(value)

The above code seems to work fine logging out a value.

I am attaching a few codes below for more clarity.

index.js or apollo setup:

import ReactDOM from 'react-dom'
import App from './App'

import {
  ApolloClient,
  ApolloProvider,
  HttpLink,
  InMemoryCache,
  split,
} from '@apollo/client'

import { setContext } from '@apollo/client/link/context'

import { getMainDefinition } from '@apollo/client/utilities'
import { GraphQLWsLink } from '@apollo/client/link/subscriptions'
import { createClient } from 'graphql-ws'
import Assess from './Asses'

const authLink = setContext((_, { headers }) => {
  const token = localStorage.getItem('library-user-token')
  return {
    headers: {
      ...headers,
      authorization: token ? `bearer ${token}` : null,
    },
  }
})

const httpLink = new HttpLink({ uri: 'http://localhost:4002' })

const wsLink = new GraphQLWsLink(
  createClient({
    url: 'ws://localhost:4002',
  })
)

const splitLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query)
    return (
      definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
    )
  },
  wsLink,
  authLink.concat(httpLink)
)

const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: splitLink,
})

ReactDOM.render(
  <ApolloProvider client={client}>
    <Assess />
  </ApolloProvider>,
  document.getElementById('root')
)

App.js

//App.js
import { useSubscription, useQuery } from "@apollo/client";
import { ALL_BOOKS, BOOK_ADDED } from "./queries";

const App = () => {
  console.log(BOOK_ADDED);
  const result = useQuery(ALL_BOOKS);
  useSubscription(BOOK_ADDED, {
    onData: ({ data }) => {
      console.log(data);
    },
  });

  console.log(result)

  if(result.loading){
    return null
  }
  return (
    <div>
      {result?.data?.allBooks.map((r) => (
        <li key={r.id}>{r.title}</li>
      ))}
    </div>
  );
};

export default App

The query and fragment:


const BOOK_DETAILS = gql`
fragment BookDetails on Books {
      title
      author {
        name
      }
      published
      genres
      id
}
  `;

export const BOOK_ADDED = gql`
  subscription {
    bookAdded {
      ...BookDetails
    }
  }
  ${BOOK_DETAILS}
`;



Solution

  • After reading the changelogs of @apollo/client. I got to know that the method demonstrated in question is only useful when the version of @apollo/client is >=3.7.0. As my version was @3.6.7 it wasn't logging the value out.

    Earlier than this version the function required an onSubscriptionData callback to perform the same operation, which is now deprecated. I have still demonstrated it below as someone using version <@3.7.0 might find it useful.

      useSubscription(BOOK_ADDED,{ 
        onSubscriptionData: ({subscriptionData: data}) =>{
          console.log(data)
        }
      })
    

    You may read the change log here.