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.
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>