Skip to main content

Queries


Queries

The simplest way to access data in ECHO from react is by using a useQuery hook on a space. This will return generic objects which can be mutated like regular JavaScript objects. useQuery<T> can also return strongly typed results as will be shown below.

Untyped queries

The first argument to useQuery from package @dxos/react-client is the space and the second is an optional filter which matches all objects which have all the keys and values specified in the filter. The return type is an iterable array of Document objects.

import React from 'react';
import { createRoot } from 'react-dom/client';

import { ClientProvider } from '@dxos/react-client';
import { useQuery, useSpaces } from '@dxos/react-client/echo';
import { useIdentity } from '@dxos/react-client/halo';

export const App = () => {
  useIdentity();
  const [space] = useSpaces();
  const tasks = useQuery(space, { type: 'task' });
  return (
    <>
      {tasks.map((task) => (
        <div key={task.id}>{task.title}</div>
      ))}
    </>
  );
};

const root = createRoot(document.getElementById('root')!);
root.render(
  <ClientProvider>
    <App />
  </ClientProvider>,
);










 















The API definition of useQuery is below. It returns a generic TypedObject type which supports the ability to set and read arbitrary keys and values. See below for how to add type safety.

useQuery([spaceOrEcho], [filter], [options], [deps])

Create subscription.

Returns: T[]

Arguments:

spaceOrEcho: Space | Echo

filter: FilterSource<T>

options: QueryOptions

deps: any[]

Typed Queries

It's possible to obtain strongly typed objects from useQuery.

Because useQuery returns tracked ECHO objects, their type must descend from TypedObject.

DXOS provides apis to define these types using Effect Schemaopen in new window.

Benefits of schema declarations
  • ability to generate type-safe data access code, which makes development faster and safer.

Consider this expression of schema declared with Effect Schema:

import { Schema as S } from '@effect/schema';

import { TypedObject } from '@dxos/echo-schema';

export class TaskType extends TypedObject({
  typename: 'dxos.org/type/Task',
  version: '0.1.0',
})({
  name: S.String,
  completed: S.optional(S.Boolean),
}) {}

Types can be used to make queries as well:

import React from 'react';
import { createRoot } from 'react-dom/client';

import { ClientProvider } from '@dxos/react-client';
import { Filter, useQuery, useSpaces } from '@dxos/react-client/echo';
import { useIdentity } from '@dxos/react-client/halo';

import { TaskType } from './schema';

export const App = () => {
  useIdentity();
  const [space] = useSpaces();
  const tasks = useQuery(space, Filter.schema(TaskType));
  return (
    <>
      {tasks.map((task) => (
        <div key={task.id}>
          {task.name} - {task.completed}
        </div>
      ))}
    </>
  );
};

const root = createRoot(document.getElementById('root')!);
root.render(
  <ClientProvider types={[TaskType]}>
    <App />
  </ClientProvider>,
);

Note the client.addTypes call which registers the types with the client.