useQuery()
无需获取即可渲染数据。
访问任意 Queryable Schema 在 store 中的值;例如 Entity、All、Collection、Query、
Union 和 Scalar。Lazy 字段也可以通过其 .query 访问器使用。如果该值不存在,则返回 undefined。
useQuery() 会响应数据变更;只在必要时重新渲染。当数据为 Invalid 时返回 undefined。
用法
Post
PostResource
PostItem
TotalVotes
PostList
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;
function useQuery<S extends Queryable>(
schema: S,
...args: SchemaArgs<S>
): DenormalizeNullable<S> | 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 的能力。
UserResource
UsersPage
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 也可以用来计算聚合值
探索 todo-app 示例
Lazy 关系
Lazy 字段在父级反规范化时保留原始 ID。将 .query 与 useQuery 搭配使用即可按需解析它们,从而把重新渲染限制在真正需要相关数据的组件内。
Resources
DepartmentsPage
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,因为它同样包含价格数据。
探索 coin-app 示例