跳到主要内容

useQuery()

无需获取即可渲染数据。

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

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

提示

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

用法​

import { Query } from '@data-client/rest';
import { useQuery } from '@data-client/react';
import { PostResource } from './PostResource';

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

export default function TotalVotes({ userId }: Props) {
  const totalVotes = useQuery(queryTotalVotes, { userId });
  return (
    <center>
      <small>{totalVotes} votes total</small>
    </center>
  );
}
interface Props {
  userId: number;
}
结果
Store▶

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

类型​

function useQuery(
schema: Queryable,
...args: SchemaArgs<typeof schema>
): DenormalizeNullable<typeof endpoint.schema> | undefined;

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 的能力。

import { All, Query } from '@data-client/rest';
import { useQuery, useFetch } from '@data-client/react';
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();
  },
);

function UsersPage() {
  useFetch(UserResource.getList);
  const users = useQuery(sortedUsers, { asc: true });
  if (!users) return <div>No users in cache yet</div>;
  return (
    <div>
      {users.map(user => (
        <div key={user.pk()}>{user.name}</div>
      ))}
    </div>
  );
}
render(<UsersPage />);
结果
Store▶

剩余 Todo 总数​

Queries 也可以用来计算聚合值

更多演示

Lazy 关系​

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

import { All } from '@data-client/rest';
import { useQuery, useFetch } from '@data-client/react';
import { DepartmentResource, Department } from './Resources';

function BuildingList({ dept }: { dept: Department }) {
  const buildings = useQuery(
    Department.schema.buildings.query,
    dept.buildings,
  );
  if (!buildings) return null;
  return <span>{buildings.map(b => b.name).join(', ')}</span>;
}

function DepartmentsPage() {
  useFetch(DepartmentResource.getList);
  const departments = useQuery(new All(Department));
  if (!departments) return <div>Loading...</div>;
  return (
    <div>
      {departments.map(dept => (
        <div key={dept.pk()}>
          <strong>{dept.name}</strong>: <BuildingList dept={dept} />
        </div>
      ))}
    </div>
  );
}
render(<DepartmentsPage />);
结果
Store▶

数据 fallback​

在这个例子中,Ticker 会通过 websocket 流不断更新。然而,Ticker 没有批量/列表获取接口——这使得在列表视图中获取价格的效率很低。

因此在这种情况下,我们可以获取 Stats 列表作为 fallback,因为它同样包含价格数据。

更多演示