vue.jsvue-reactivityurql

Computed property not working when using `Object.values()`


I'm using the urql GraphQL-Client to run a bunch of queries in a component. I want to create a loading computed prop indicating if any of these queries are running. To be able to easily compute this, I wrapped the queries in an object:

const gql = {
  queryA: doQueryA(),
  queryB: doQueryB(),
  queryC: doQueryC()
};

which should allow me to compute the loading state like:

// does not work
const loading = computed(() => Object.values(gql).some(query => query.fetching));

however, this does not update once all queries are done. Doing it explicitly works:

// works
const loading = computed(() =>
  gql.queryA.fetching ||
  gql.queryB.fetching ||
  gql.queryC.fetching
);

which made me think that since .some can return early, maybe that's a problem for Vues reactivity tracking. So I tried to force it to access every query every time:

// does not work
const loading = computed(() => Object.values(gql)
  .map(query => query.fetching)
  .some(isFetching => isFetching));

However, that does not help either.

Can somebody explain why this problem exists?


Solution

  • Urql's .fetching is a ref<boolean>. That means that the code needs to be adjusted to

    const loading = computed(() => Object.values(gql)
      .map(query => query.fetching)
      .some(isFetching => isFetching.value)); // add .value access
    

    otherwise the reference that is isFetching will always be truthy.

    Then how did the other example work? Well, it all comes down to the fact that "" || 7 is not true but 7. So ref(false) || ref(true) will just be ref(false). Effectively, my loading property was just tracking the first of all the queries, which gave the impression that it was at least doing something. Not the right thing, though.