loro-mirror-jotai
v1.1.2
Published
Jotai atoms for Loro Mirror: CRDT-backed atomic state with typed schema and bidirectional sync.
Maintainers
Readme
Loro Mirror for Jotai
Jotai integration for Loro Mirror, providing atomic state management with Loro CRDT synchronization.
Installation
# Using pnpm
pnpm add loro-mirror-jotai jotai loro-crdt
# Using npm
npm install loro-mirror-jotai jotai loro-crdt
# Using yarn
yarn add loro-mirror-jotai jotai loro-crdtUsage
Create a loroMirrorAtom to represent your shared state. It syncs automatically
with the provided Loro document.
import { useAtom } from 'jotai';
import { LoroDoc } from 'loro-crdt';
import { schema } from 'loro-mirror';
import { loroMirrorAtom } from 'loro-mirror-jotai';
type TodoStatus = "todo" | "inProgress" | "done";
const todoSchema = schema.LoroMap(
{
text: schema.String(),
status: schema.String<TodoStatus>()
}
)
// Define your schema
const todoDocSchema = schema({
todos: schema.LoroList(
todoSchema,
(t) => t.$cid, // stable LoroMap id from Loro container id
)
});
// Auto generated type from schema
type Todo = InferType<typeof todoSchema>;
// Create a Loro document instance
const doc = new LoroDoc();
// Maybe subscribe the doc for persisting
let sub = doc.subscribe(......)
// Create the Jotai atom with Loro Mirror config
const todoDocAtom = loroMirrorAtom({
doc,
schema: todoDocSchema,
initialState: { todos: [] as Todo[] },
});
// Selector atom
const todosAtom = atom(get => get(todoDocAtom).todos, (_get, set, todos: Todo[]) => {
set(todoDocAtom, { todos })
})
// Action atom
const addTodoAtom = atom(null, (get, set, todo: Todo) => {
set(todosAtom, [...get(todosAtom), todo])
})
// Use it in your React component
function TodoApp() {
const todos = useAtomValue(todosAtom);
const addTodo = useSetAtom(addTodoAtom);
return (
<div>
<button onClick={()=>{
addTodo({text: "New todo", status: "todo"})
}}>Add Todo</button>
<ul>
{state.todos.map((todo) => (
<li key={todo.$cid /* stable key from Loro container id */}>
{todo.text}: {todo.status}
</li>
))}
</ul>
</div>
);
}About $cid
$cidis always present onLoroMapstate and equals the underlying Loro container id.- Use
$cidas a stable list selector and React key:schema.LoroList(item, x => x.$cid)and<li key={todo.$cid}>.
