Search code examples
reactjsgraphqlexpress-graphqlreact-relay

RelayObservable: Unhandled Error TypeError: Cannot read property 'subscribe' of undefined in React and Relay


I have followed the subscription tutorial on How to GraphQL React + Relay (https://relay.dev/docs/en/subscriptions) but still not working.

I'm using Relay Modern in my app and have successfully integrated query but not working the requestSubscription function.

Any help would be awesome.

My environment.js file:

function setupSubscription(
  config,
  variables,
  cacheConfig,
  observer,
) {
  const query = config.text
  const subscriptionClient = new SubscriptionClient('ws://192.168.1.19:8000/subscriptions', {reconnect: true});
  const id = subscriptionClient.on({query, variables}, (error, result) => {
    console.log(result,'result');
    observer.onNext({data: result})
  })
}
const network = Network.create(fetchQuery, setupSubscription)

const environment = new Environment({
  network,
  store
});

export default environment;

- My Subscription.js file:

const subscription = graphql`
      subscription newVoteSubscription {
        leaderboardUpdate {
          id,
          game_id,
          event_id,
          colarr,
          rowarr
        }
      }
    `;
    function newVoteSubscription(callback) {
      const variables = {};
      return requestSubscription(environment, {
        subscription: subscription,
        variables: variables,
        onError: (error)=> {
          console.log(error, "error");
        },
        onNext: (res) => {
          console.log(res,'onNext');
          // callback();
        },
        updater: proxyStore => {
          console.log(proxyStore,'proxyStore');
        },
        onCompleted: () => {
          console.log('test');
        },
      });
    }

    export default newVoteSubscription;

enter image description here


Solution

  • I had trouble with the network as well. On Relay 7 using an Observable worked for me. This also handles error cases and the server closing the subscription.

    const subscriptionClient = new SubscriptionClient('ws://192.168.1.19:8000/subscriptions', {reconnect: true})
    
    function setupSubscription(
      request,
      variables,
      cacheConfig,
    ) {
      const query = request.text;
    
      // Observable is imported from the relay-runtime package
      return Observable.create(sink => {
        const c = subscriptionClient.request({ query, variables }).subscribe(sink);
        return c.unsubscribe;
      });
    }
    

    I'm not sure why i've gone with the sink / unsubscribe approach, but this is what worked for me. As far as i remember the observable types used by relay and subscriptions-transport-ws were not compatible.

    Also i'd advise you to hoist the new SubscriptionClient() call outside of the setupSubscription function as otherwise you'll open a new WebSocket for each subscription request.