Saltar al contenido principal

Query

Query ofrece acceso programático a la caché de Reactive Data Client manteniendo el mismo alto rendimiento y las mismas garantías de igualdad referencial que se esperan de Reactive Data Client.

Query se puede renderizar usando la búsqueda por schema con el hook useQuery()

Miembros de Query​

schema​

Schema usado para recuperar y desnormalizar datos de la caché de Reactive Data Client. Acepta cualquier schema Queryable: Entity, All, Collection, Query, Union, Scalar y schemas de Object para unir varias entidades. Los campos Lazy producen un Queryable mediante su acceso .query.

process(entries, ...args)​

Recibe la respuesta (desnormalizada) como entries, junto con los argumentos, y devuelve la nueva respuesta para usar con useQuery

Uso​

Mantener el orden tras crear elementos​

import { Collection, Entity, Query, RestEndpoint } from '@data-client/rest';

export class Post extends Entity {
  id = '';
  title = '';
  group = '';
  author = '';
}

export const getPosts = new RestEndpoint({
  path: '/:group/posts',
  searchParams: {} as { orderBy?: string; author?: string },
  schema: new Query(
    new Collection([Post], {
      nonFilterArgumentKeys: /orderBy/,
    }),
    (posts, { orderBy } = {}) => {
      if (orderBy) {
        return [...posts].sort((a, b) =>
          a[orderBy].localeCompare(b[orderBy]),
        );
      }
      return posts;
    },
  ),
});
Resultado
Store▶

Agregados​

Fixtures
GET /users
[{"id":"123","name":"Jim"},{"id":"456","name":"Jane"},{"id":"777","name":"Albatras","isAdmin":true}]
▶resources/User
▶UsersPage
import { All, Query } from '@data-client/rest';
import { useQuery, useFetch } from '@data-client/react';
import { UserResource, User } from './resources/User';

const countUsers = new Query(
  new All(User),
  (entries, { isAdmin } = {}) => {
    if (isAdmin !== undefined)
      return entries.filter(user => user.isAdmin === isAdmin).length;
    return entries.length;
  },
);

function UsersPage() {
  useFetch(UserResource.getList);
  const userCount = useQuery(countUsers);
  const adminCount = useQuery(countUsers, { isAdmin: true });
  if (userCount === undefined) return <div>No users in cache yet</div>;
  return (
    <div>
      <div>Total users: {userCount}</div>
      <div>Total admins: {adminCount}</div>
    </div>
  );
}
render(<UsersPage />);
Resultado
Store▶

Reorganizar datos con agregaciones groupBy​

▶resources/User
▶resources/Todo
▶TodoByUser
▶TodoJoined
import { Query } from '@data-client/rest';
import { useQuery, useFetch, useSuspense } from '@data-client/react';
import { TodoResource } from './resources/Todo';
import { UserResource } from './resources/User';
import TodoByUser from './TodoByUser';

const groupTodoByUser = new Query(
  TodoResource.getList.schema,
  todos => Object.groupBy(todos, todo => todo.userId),
);

function TodosPage() {
  useFetch(UserResource.getList);
  useSuspense(TodoResource.getList);
  useSuspense(UserResource.getList);
  const todosByUser = useQuery(groupTodoByUser);
  if (!todosByUser) return <div>Todos not found</div>;
  return (
    <div>
      {Object.keys(todosByUser).slice(5).map(userId => (
        <TodoByUser
          key={userId}
          userId={userId}
          todos={todosByUser[userId]}
        />
      ))}
    </div>
  );
}
render(<TodosPage />);
Resultado
Store▶

Uniones con Object Schema​

Query puede recibir Object Schemas, lo que permite unir varios tipos de entidad. Esto te permite combinar datos de distintas entidades en una sola consulta.

Fixtures
GET /tickers/BTC-USD
{"product_id":"BTC-USD","price":45000}
GET /stats/BTC-USD
{"product_id":"BTC-USD","last":44950}
▶resources/Ticker
▶resources/Stats
▶PriceDisplay
import { Query } from '@data-client/rest';
import { useQuery, useFetch } from '@data-client/react';
import { TickerResource, Ticker } from './resources/Ticker';
import { StatsResource, Stats } from './resources/Stats';

// Join Ticker and Stats by product_id
const queryPrice = new Query(
  { ticker: Ticker, stats: Stats },
  ({ ticker, stats }) => ticker?.price ?? stats?.last,
);

function PriceDisplay({ productId }: { productId: string }) {
  useFetch(TickerResource.get, { product_id: productId });
  useFetch(StatsResource.get, { product_id: productId });
  const price = useQuery(queryPrice, { product_id: productId });
  
  if (price === undefined) return <div>Loading...</div>;
  return <div>Price: ${price}</div>;
}

render(<PriceDisplay productId="BTC-USD" />);
Resultado
Store▶

Uniones de reserva​

En este caso Ticker se actualiza constantemente desde un stream de websocket. Sin embargo, no existe un fetch masivo o de lista para Ticker, lo que lo hace ineficiente para obtener los precios en una vista de lista.

Así que en este caso podemos obtener una lista de Stats como alternativa, ya que también contiene datos de precios.

Explora el ejemplo coin-app

More Demos