# Any way to subscribe for network status of queryRef?

**URL:** <https://community.apollographql.com/t/any-way-to-subscribe-for-network-status-of-queryref/9030>\
**Category:** Client SDKs\
**Created:** [May 12, 2025, 4:59pm UTC](https://community.apollographql.com/t/any-way-to-subscribe-for-network-status-of-queryref/9030 "2025-05-12T16:59:42Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![misha-erm](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/misha-erm/32/5056_2.png) [@misha-erm](https://community.apollographql.com/u/misha-erm)\
**Post date:** [May 12, 2025, 4:59pm UTC](https://community.apollographql.com/t/any-way-to-subscribe-for-network-status-of-queryref/9030/1 "2025-05-12T16:59:42Z")

</div>

Hello,  
I’m building some search experience and would like to know if there is any way to subscribe for queryRef network status without using suspense?

So I have a search input and on change I update query params. When query params are updated my preloadQuery activates and refetches with new query string (I’m using react-router 7 loaders). Everything works fine but I’d like to display some spinner inside my search input. What’s the best way of doing this? Switching to useLazyQuery?

I assume this can be implemented with suspense APIs as well,e.g.

```auto
const MonitorNetworkStatus = () => {
    useReadQuery(queryRef);
}
...

<Suspense fallback={<Spinner/>}>
  <MonitorNetworkStatus queryRef={queryRef} />
</Suspense>

```

but this doesn’t feel very natural

Thanks in advance for any tips 🙇

---

<div class="post-metadata">

**Author:** ![jerelmiller](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/jerelmiller/32/3314_2.png) [@jerelmiller](https://community.apollographql.com/u/jerelmiller)\
**Post date:** [May 12, 2025, 6:01pm UTC](https://community.apollographql.com/t/any-way-to-subscribe-for-network-status-of-queryref/9030/2 "2025-05-12T18:01:36Z")

</div>

Hey @misha-erm 👋

Would you mind providing some more code and context on how query params and everything else plays into that `queryRef`? This may be tricky due to how Suspense works, but I’d like to see how you’re setting everything up before I can confidently provide an answer here 🙂

---

<div class="post-metadata">

**Author:** ![misha-erm](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/misha-erm/32/5056_2.png) [@misha-erm](https://community.apollographql.com/u/misha-erm)\
**Post date:** [May 12, 2025, 6:16pm UTC](https://community.apollographql.com/t/any-way-to-subscribe-for-network-status-of-queryref/9030/3 "2025-05-12T18:16:36Z")

</div>

Sure

So here is an example of UI

 ![image](https://us1.discourse-cdn.com/flex019/uploads/apollographql/original/2X/5/5aa02b4c2f3e16c1d302ddd6118349e2480cfe9f.jpeg)

Here is the code for my Search Input:

```auto
export const StreamPostsSearch = () => {
  const { q } = useStreamPostsLoaderData();

  const [, setSearchParams] = useSearchParams();

  const debouncedSetSearchParams = useDebouncedCallback(setSearchParams, 200);

  const onValueChange = useCallback(
    (value?: string) => {
      const query = value || '';
      if (query.length === 0) {
        setSearchParams((prev) => deleteSearchParams(prev, ['q']), {
          preventScrollReset: true,
        });
        debouncedSetSearchParams.cancel();
      } else {
        debouncedSetSearchParams({ q: query }, { preventScrollReset: true });
      }
    },
    [debouncedSetSearchParams, setSearchParams],
  );

  return (
    <SearchInput
      placeholder="Filter posts..."
      onQueryChange={onValueChange}
      defaultValue={q}
    />
  );
};

```

and react-router loader looks like this:

```auto
const SearchStreamPostsQuery = gql(`
  query SearchStreamPostsQuery($query: String!, $streamId: ID!, $limit: Int!, $offset: Int!) {
    searchStreamPosts(input: {streamId: $streamId, text: $query, limit: $limit, offset: $offset}) {
      items {
        ... on StreamPost {
          ...StreamPostCardFragment
        }
      }
    }
  }
  `);

export const clientLoader = ({
  request,
  params,
}: Route.ClientLoaderArgs) => {
  const searchParams = new URL(request.url).searchParams;
  const q = (searchParams.get('q') || '').trim();

  return {
    q,
    searchStreamPostsQueryRef: q
      ? preloadQuery(SearchStreamPostsQuery, {
          variables: {
            streamId: params.id,
            query: q,
            limit: 20,
            offset: 0,
          },
          fetchPolicy: 'network-only',
        })
      : null,
  };
};

```

later in the code I do something like

```auto
const {searchStreamPostsQueryRef} = useLoaderData();

return searchStreamPostsQueryRef ? <SearchFeed/> :  

return (<Container after={<StreamPostsSearch/>}>
  <Suspense fallback={<Skeleton/>}>
    {searchStreamPostsQueryRef ? <SearchFeed queryRef={searchStreamPostsQueryRef} /> : <RegularFeed/>}
  </Suspense>
</Container>);

```

So I was thinking about the way of rendering spinner icon inside StreamPostsSearch in addition or instead of skeleton

Will this be enough or better to prepare the sandbox?

---

<div class="post-metadata">

**Author:** ![jerelmiller](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/jerelmiller/32/3314_2.png) [@jerelmiller](https://community.apollographql.com/u/jerelmiller)\
**Post date:** [May 12, 2025, 6:27pm UTC](https://community.apollographql.com/t/any-way-to-subscribe-for-network-status-of-queryref/9030/4 "2025-05-12T18:27:07Z")

</div>

This helps. Thanks!

So this one is a bit tricky due to how Suspense works. Unfortunately `networkStatus` isn’t going to help much here because you’ll never have a render where you can observe `networkStatus: NetworkStatus.loading` since this state means you have a pending promise which will trigger your suspense boundary. The only time you’ll really only be able to observe `networkStatus` as something other than `ready` is if you’re using the `cache-and-network` `fetchPolicy` and a stale result is emitted while the fetch from the network is kicked off (we suspend until that cache result is returned, then update `data`/`networkStatus` once the network is finished).

Your best bet is to use transitions in order to prevent your Suspense fallback from showing up. If a state update is done in a transition, React will try and render your component and if that state update causes that render to suspend, it will show your old UI until the transition is complete (i.e. the promise resolves).

I would try adding a [`useTransition`](https://react.dev/reference/react/useTransition) inside your `StreamPostsSearch` component and wrapping your `setSearchParams` in `startTransition` returned from that hook. You can use that `isPending` flag to determine if you’re in a transition or not and use this to show a loading indicator with your `SearchInput`. That transition _should_ see that your search params update causes your component to suspend and show your old UI. Try this out and see if this works for you 🙂

---

<div class="post-metadata">

**Author:** ![misha-erm](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/misha-erm/32/5056_2.png) [@misha-erm](https://community.apollographql.com/u/misha-erm)\
**Post date:** [May 12, 2025, 9:13pm UTC](https://community.apollographql.com/t/any-way-to-subscribe-for-network-status-of-queryref/9030/5 "2025-05-12T21:13:01Z")

</div>

awesome, thank you 🙇

Completely missed the fact that `useTransition` can do the trick there

---

<div class="post-metadata">

**Author:** ![jerelmiller](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/jerelmiller/32/3314_2.png) [@jerelmiller](https://community.apollographql.com/u/jerelmiller)\
**Post date:** [May 12, 2025, 9:23pm UTC](https://community.apollographql.com/t/any-way-to-subscribe-for-network-status-of-queryref/9030/6 "2025-05-12T21:23:50Z")

</div>

No problem! Glad that helped!
