useQuery()
Query the store.
Renders any Queryable Schema like Entity, All, Collection, Query, and Union from the store.
Queries are a great companion to efficiently render aggregate computations like those that use groupBy, map, reduce, and filter.
useQuery()
is reactive to data mutations; rerendering only when necessary. Returns undefined
when data is Invalid.
Usage
import { schema } from '@data-client/rest'; import { useQuery } from '@data-client/react'; import { Post } from './PostResource'; const queryTotalVotes = new schema.Query( new schema.All(Post), (posts, { userId } = {}) => { if (userId !== undefined) posts = posts.filter(post => post.author.id === userId); return 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; }
See truthiness narrowing for more information about type handling
Types
- Type
- With Generics
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 schemas require an queryKey()
method that returns something. These include
Entity, All, Collection, Query,
and Union.
interface Queryable {
queryKey(
args: readonly any[],
queryKey: (...args: any) => any,
getEntity: GetEntity,
getIndex: GetIndex,
// Must be non-void
): {};
}
Examples
Sorting & Filtering
Query provides programmatic access to the Reactive Data Client store.
import { schema } 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 schema.Query( new schema.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 />);
Remaining Todo total
Queries can also be used to compute aggregates
Data fallbacks
In this case Ticker
is constantly updated from a websocket stream. However, there is no bulk/list
fetch for Ticker
- making it inefficient for getting the prices on a list view.
So in this case we can fetch a list of Stats
as a fallback since it has price data as well.