Skip to content

Access to the networkStatus #18

@obedm503

Description

@obedm503

I'd like to access the networkStatus property to know when a query is refetching. Currently loading only works for the initial load but not subsequent loads even with the notifyOnNetworkStatusChange option.

The way the createQuery function is implemented, it only exposes the data instead of the whole ApolloQueryResult. I ended up implementing my own createQuery that exposes the whole result object.

export const createQuery = <TData = {}, TVariables = OperationVariables>(
  query: DocumentNode<TData, TVariables>,
  options: CreateQueryOptions<TData, TVariables> = {},
) => {
  const apolloClient = useApollo();

  const optionsAccessor = () => {
    if (typeof options !== 'function') {
      if (options.skip) {
        console.warn(
          'you passed options.skip to createQuery, but the options are not an acccessor.\nThis query will never execute!\n\nReplace your options with a function.',
        );
      }

      return options;
    }
    const opts = typeof options === 'function' ? options() : options;
    if (opts.skip) {
      return false;
    }
    return opts;
  };

  const [resource] = createResource<
    ApolloQueryResult<TData>,
    BaseOptions<TData, TVariables>
  >(optionsAccessor, (opts) => {
    const observable = apolloClient.watchQuery<TData, TVariables>({
      query,
      ...opts,
    });
    const [state, setState] = createStore<ApolloQueryResult<TData>>({
      data: undefined as any,
      loading: true,
      networkStatus: NetworkStatus.loading,
    });

    const sub = observable.subscribe({
      error: (error) => {
        setState(
          reconcile({
            loading: false,
            networkStatus: NetworkStatus.error,
            error,
            data: undefined as any,
          }),
        );
      },
      next: (result) => {
        setState(result);
      },
    });

    onCleanup(() => sub.unsubscribe());

    return state;
  });

  return resource;
};

This does mean I have to access resource()?.loading instead resource.loading and resource()?.data instead resource().

Are you interested in using something like this? Is there a better way to do it?

One immediate improvement would be figuring out how to make the resource always return a ApolloQueryResult<TData> instead of a ApolloQueryResult<TData> | undefined.

Another possible solution is to just use from to wrap watchQuery.

const createQuery = <TData, TVariables = OperationVariables>(
  query: DocumentNode<TData, TVariables>,
  options: CreateQueryOptions<TData, TVariables> = {},
) => {
  const apolloClient = useApollo();

  const optionsAccessor = () => {
    if (typeof options !== 'function') {
      if (options.skip) {
        console.warn(
          'you passed options.skip to createQuery, but the options are not an acccessor.\nThis query will never execute!\n\nReplace your options with a function.',
        );
      }

      return options;
    }
    const opts = typeof options === 'function' ? options() : options;
    if (opts.skip) {
      // no skip possible with from?
      return {};
    }
    return opts;
  };

  return from<ApolloQueryResult<TData>>((set) => {
    const observable = apolloClient.watchQuery<TData, TVariables>({
      query,
      ...optionsAccessor(),
    });
    const sub = observable.subscribe({
      error: (error) => {
        set(
          reconcile({
            loading: false,
            networkStatus: NetworkStatus.error,
            error,
            data: undefined as any,
          }),
        );
      },
      next: (result) => {
        set(result);
      },
    });
    return () => sub.unsubscribe();
  });
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions