Skip to content

Mutations in React

Mutating objects in ECHO is as simple as directly manipulating them like normal JavaScript objects.

When an object comes out of an ECHO query, it is tracked by framework and any changes to it will be issued to the peer network and applied to all connected clients reactively. Other clients see their useQuery hooks and query subscriptions fire when the changes come in.

Untyped Mutations

Setting values

In the example below, clicking a task sets completed = true.

import React from 'react';
import { createRoot } from 'react-dom/client';
import { ClientProvider } from '@dxos/react-client';
import { Expando, live, 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}
onClick={() => {
task.completed = true;
}}
>
{task.name} - {task.completed}
</div>
))}
<button
name='add'
onClick={() => {
const task = live(Expando, { type: 'task', name: 'buy milk' });
space?.db.add(task);
}}
>
Add a task
</button>
</>
);
};
const root = createRoot(document.getElementById('root')!);
root.render(
<ClientProvider>
<App />
</ClientProvider>,
);

Creating objects

To create (insert) a new object, simply construct a new Expando and pass any initial values into the constructor.

Typed Mutations

The following example uses the same schema definition as in the Typed Queries section.

Setting values

In the example below, clicking a task sets completed = true in the same way as the untyped API.

import React from 'react';
import { createRoot } from 'react-dom/client';
import { ClientProvider } from '@dxos/react-client';
import { Filter, live, 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.type(TaskType));
return (
<>
{tasks.map((task) => (
<div
key={task.id}
onClick={() => {
task.completed = true;
}}
>
{task.name} - {task.completed}
</div>
))}
<button
name='add'
onClick={() => {
const task = live(TaskType, { name: 'buy milk' });
space?.db.add(task);
}}
>
Add a task
</button>
</>
);
};
const root = createRoot(document.getElementById('root')!);
root.render(
<ClientProvider types={[TaskType]}>
<App />
</ClientProvider>,
);

Creating objects

To create (insert) a new object, construct a new one with the create function and pass any initial values in.

Removing objects

To remove an object (typed or untyped) call the remove API on a space.

space.db.remove(task);