Have I NOT been using cache with this pattern?

I used to fire a query like:

const { loading, error, data } = useQuery(GET_DOGS, {
  fetchPolicy: 'cache-and-network', // Doesn't check cache before making a network request

and later in the code do something like:

loading ? <Loader> : data.map...

Does this pattern actually make app behave as if I used fetchPolicy: ‘network-only’?
If I understand the docs correctly what happens is:

  1. Apollo makes the call anyway
  2. It checks whether data is available in the cache and if so it returns cached data.
  3. When HTTP call is finished data is updated with what’s been returned and so is cache

If this reasoning is correct, to make use of cache I should do something in a fashion of:

!data && loading  && <Loader>
data ? data.map... : null 

I would love to get second opinion on that, as it would mean dramatic performance differences for my app.

Yup, your suspicions are correct. Your last code sample should do the trick. In our app we display both the loader AND the data if there is cached data available while loading.