跳到主要内容

useQuery()

无需获取即可渲染数据。

访问任意 Queryable Schema 在 store 中的值;例如 Entity、All、Collection、Query、 Union 和 Scalar。Lazy 字段也可以通过其 .query 访问器使用。如果该值不存在,则返回 undefined。

useQuery() 会响应数据变更;只在必要时重新渲染。当数据为 Invalid 时返回 undefined。

提示

Queries 是高效渲染聚合计算的好帮手,例如使用 groupBy、 map、reduce 和 filter 的计算。

用法​

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

关于类型处理的更多信息,请参阅真值收窄

类型​

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

参数可以是普通值、refs(包括 computed),或者像 () => ({ id: props.id }) 这样的 getter 函数。像 { id: props.id } 这样的普通对象只会被读取一次,不会跟随 prop 或路由的变化,因此当参数可能变化时,请使用 getter 或 computed。

参数变化时,结果会随之更新。

Queryable​

Queryable schema 需要一个有返回值的 queryKey() 方法。这包括 Entity、All、Collection、Query、 Union 和 Scalar。Lazy 字段通过其 .query 访问器产生一个 Queryable。

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

示例​

排序与过滤​

Query 提供了以编程方式访问 Reactive Data Client store 的能力。

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

Lazy 关系​

Lazy 字段在父级反规范化时保留原始 ID。将 .query 与 useQuery 搭配使用即可按需解析它们,从而把重新渲染限制在真正需要相关数据的组件内。

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