react-apollo icon indicating copy to clipboard operation
react-apollo copied to clipboard

Subscription component loading forever

Open JaEdmuva opened this issue 6 years ago • 7 comments

Intended outcome:

Get data from subscription using Subscription component from @apollo/react-components. Result data should be updated, including loading value.

<Subscription subscription={SUBSCRIPTION} client={client}> {this.myFunction} </Subscription> Client is created using this:

export const createClient = ({ uri, ws }) => new ApolloClient({ defaultOptions: { watchQuery: { fetchPolicy: 'cache-and-network', }, }, cache, link: ApolloLink.from([ ApolloLogger, onError(({ graphQLErrors, networkError }) => { if (graphQLErrors) { graphQLErrors.map(({ message, locations, path }) => console.log([GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path} ) ); } if (networkError) { console.log([Network error]: ${networkError}`); } }), new RetryLink({ attempts: { max: Infinity } }).split( ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' ); }, new WebSocketLink({ uri: ws, options: { reconnect: true, }, }), new HttpLink({ uri, credentials: 'same-origin', }) ), ]), typeDefs, resolvers, });

` Actual outcome:

Result data does not get updated, even when apollo-link-logger shows the result in the console. Simple console.log(result) is being used in myFunction to see the callback results. First time it's rendered it logs with loading=true. It never gets called again with loading=false or any other data (no console.log printed).

How to reproduce the issue:

Normally this will happen with subscriptions. Every now and then it works as expected, but most of the time it just does not work.

Version

System: OS: macOS 10.14.6 Binaries: Node: 10.16.2 - ~/.nvm/versions/node/v10.16.2/bin/node Yarn: 1.17.3 - /usr/local/bin/yarn npm: 6.9.0 - ~/.nvm/versions/node/v10.16.2/bin/npm Browsers: Chrome: 76.0.3809.100 Safari: 12.1.2 npmPackages: apollo-cache-inmemory: ^1.6.3 => 1.6.3 apollo-cache-persist: ^0.1.1 => 0.1.1 apollo-client: ^2.6.4 => 2.6.4 apollo-link: ^1.2.12 => 1.2.12 apollo-link-error: ^1.1.11 => 1.1.11 apollo-link-http: ^1.5.15 => 1.5.15 apollo-link-logger: ^1.2.3 => 1.2.3 apollo-link-rest: ^0.7.3 => 0.7.3 apollo-link-retry: ^2.2.14 => 2.2.14 apollo-link-ws: ^1.0.18 => 1.0.18 apollo-utilities: ^1.3.2 => 1.3.2

JaEdmuva avatar Aug 28 '19 16:08 JaEdmuva

Any chance you can provide a small runnable reproduction that shows this happening?

hwillson avatar Sep 06 '19 12:09 hwillson

I was facing this as well. The WS was still receiving all messages just fine, but for some reason the values within the useSubscription hook got staled. My guess is when the server responds too fast (under the 100ms ish) it could make this to happen.

The workaround I did relies on the onSubscriptionData, like below

const [values, setValues] = useState<
    Partial<SubscriptionResult<SubscribeActivePromotion>>
  >({});

  useSubscription<SubscribeActivePromotion, SubscribeActivePromotionVariables>(
    subscribeActivePromotion,
    {
      onSubscriptionData(options) {
        setValues(() => options.subscriptionData);
      },
      variables: {
        partnerId: props.partnerId,
      },
    }
  );

schettino avatar Sep 10 '19 16:09 schettino

Having the same problem. The workaround @schettino suggested is working for me! :)

pkvince avatar Sep 11 '19 16:09 pkvince

@hwillson not able to provide a runnable right now since I'm using react native. If it guides you better, it's very likely to reproduce when debug is enabled and dev tools hooked.

JaEdmuva avatar Oct 31 '19 22:10 JaEdmuva

I have the same issue. Workaround from @schettino works great with one small addition - don't forget to pass { loading: true } when initializing state.

const useSubscription = <TData, TVariables>(
  query: DocumentNode,
  options?: SubscriptionHookOptions<TData, TVariables>,
) => (variables: TVariables) => {
  const [values, setValues] = useState<Partial<SubscriptionResult<TData>>>({
    loading: true
  });
  __useSubscription<TData, TVariables>(
    query,
    {
      ...options,
      variables,
      onSubscriptionData: (options) => {
        setValues(() => options.subscriptionData);
      }
    }
  );
  return values;
};

semenovDL avatar Dec 09 '19 15:12 semenovDL

I have the same issue, subscription keeps loading at first initialize, reload the app it's work without issue. I try to set lazy in subscription options to true and it's work on my case.

DanielRNDev avatar Feb 09 '20 16:02 DanielRNDev

Probably related: https://github.com/apollographql/react-apollo/issues/3802

Root cause: As identified in the video, I believe the root cause is a race condition in /packages/hooks/src/data/SubscriptionData.ts which implicitly requires that isMounted will be set to true before updateResult is called, and this is not always the case.

0xdevalias avatar Apr 03 '20 04:04 0xdevalias