Saltar al contenido principal

useQuery()

Renderizado de datos sin el fetch.

Accede al valor en el store de cualquier Queryable Schema; como Entity, All, Collection, Query, Union y Scalar. Los campos Lazy también funcionan mediante su accesor .query. Si el valor no existe, devuelve undefined.

useQuery() reacciona a las mutaciones de datos; vuelve a renderizar solo cuando es necesario. Devuelve undefined cuando los datos son Invalid.

consejo

Las Queries son un gran complemento para renderizar de forma eficiente cálculos agregados, como los que usan groupBy, map, reduce y filter.

Uso​

<script setup lang="ts">
  import { Query } from '@data-client/rest';
  import { useQuery } from '@data-client/vue';
  import { PostResource } from './PostResource';

  const queryTotalVotes = new Query(
    PostResource.getList.schema,
    posts => posts.reduce((total, post) => total + post.votes, 0),
  );

  const props = defineProps<{ userId: number }>();
  const totalVotes = useQuery(queryTotalVotes, () => ({ userId: props.userId }));
</script>

<template>
  <div style="text-align: center">
    <small>{{ totalVotes }} votes total</small>
  </div>
</template>

Consulta truthiness narrowing para más información sobre el manejo de tipos

Tipos​

function useQuery<S extends Queryable>(
schema: S,
...args: MaybeRefsOrGetters<SchemaArgs<S>>
): ComputedRef<DenormalizeNullable<S> | undefined>;

Los argumentos pueden ser valores simples, refs (incluidos los computed) o funciones getter como () => ({ id: props.id }). Un objeto simple como { id: props.id } se lee una sola vez y no seguirá los cambios de props ni de ruta, así que usa un getter o computed cuando un argumento pueda cambiar.

El resultado se actualiza cuando cambian los argumentos.

Queryable​

Los schemas Queryable requieren un método queryKey() que devuelva algo. Entre ellos están Entity, All, Collection, Query, Union y Scalar. Los campos Lazy producen un Queryable mediante su accesor .query.

interface Queryable {
queryKey(
args: readonly any[],
queryKey: (...args: any) => any,
getEntity: GetEntity,
getIndex: GetIndex,
// Must be non-void
): {};
}

Ejemplos​

Ordenación y filtrado​

Query proporciona acceso programático al store de Reactive Data Client.

<script setup lang="ts">
  import { Query, All } from '@data-client/rest';
  import { useQuery, useFetch } from '@data-client/vue';
  import { UserResource, User } from './UserResource';

  interface Args {
    asc: boolean;
    isAdmin?: boolean;
  }
  const sortedUsers = new Query(
    new All(User),
    (entries, { asc, isAdmin }: Args = { asc: false }) => {
      let sorted = [...entries].sort((a, b) =>
        a.name.localeCompare(b.name),
      );
      if (isAdmin !== undefined)
        sorted = sorted.filter(user => user.isAdmin === isAdmin);
      if (asc) return sorted;
      return sorted.reverse();
    },
  );

  useFetch(UserResource.getList);
  const users = useQuery(sortedUsers, { asc: true });
</script>

<template>
  <div v-if="!users">No users in cache yet</div>
  <div v-else>
    <div v-for="user in users" :key="user.pk()">{{ user.name }}</div>
  </div>
</template>

Relaciones Lazy​

Los campos Lazy conservan los IDs sin resolver durante la desnormalización del padre. Usa .query con useQuery para resolverlos bajo demanda, limitando los re-renderizados únicamente a los componentes que necesitan los datos relacionados.

<script setup lang="ts">
  import { computed } from 'vue';
  import { useQuery } from '@data-client/vue';
  import { Department } from './Resources';

  const props = defineProps<{ dept: Department }>();

  const buildings = useQuery(
    Department.schema.buildings.query,
    computed(() => props.dept.buildings),
  );
</script>

<template>
  <span v-if="buildings">{{ buildings.map(b => b.name).join(', ') }}</span>
</template>
<script setup lang="ts">
  import { All } from '@data-client/rest';
  import { useQuery, useFetch } from '@data-client/vue';
  import { DepartmentResource, Department } from './Resources';
  import BuildingList from './BuildingList.vue';

  useFetch(DepartmentResource.getList);
  const departments = useQuery(new All(Department));
</script>

<template>
  <div v-if="!departments">Loading...</div>
  <div v-else>
    <div v-for="dept in departments" :key="dept.pk()">
      <strong>{{ dept.name }}</strong>: <BuildingList :dept="dept" />
    </div>
  </div>
</template>