Socket
Book a DemoInstallSign in
Socket

loro-mirror-react

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

loro-mirror-react

React hooks and context for Loro Mirror: type-safe CRDT-backed state with selective subscriptions.

latest
npmnpm
Version
1.2.1
Version published
Maintainers
1
Created
Source

Loro Mirror React

React integration for Loro Mirror - a state management library with Loro CRDT synchronization.

Installation

npm install loro-mirror-react loro-mirror loro-crdt
# or
yarn add loro-mirror-react loro-mirror loro-crdt
# or
pnpm add loro-mirror-react loro-mirror loro-crdt

Usage

Basic Usage with Hooks

import React, { useMemo } from "react";
import { LoroDoc } from "loro-crdt";
import { schema } from "loro-mirror";
import { useLoroStore } from "loro-mirror-react";

// Define your schema
const todoSchema = schema({
    todos: schema.LoroList(
        schema.LoroMap({
            text: schema.String({ required: true }),
            completed: schema.Boolean({ defaultValue: false }),
        }),
        // Use `$cid` (reuses Loro container id; explained below)
        (item) => item.$cid,
    ),
    filter: schema.String({ defaultValue: "all" }),
});

function TodoApp() {
    // Create a Loro document
    const doc = useMemo(() => new LoroDoc(), []);

    // Create a store
    const { state, setState } = useLoroStore({
        doc,
        schema: todoSchema,
        initialState: { todos: [], filter: "all" },
    });

    // Add a new todo (synchronous; the update is applied before return)
    const addTodo = (text: string) => {
        setState((s) => ({
            ...s,
            todos: [...s.todos, { text, completed: false }],
        }));
    };

    // Rest of your component...
}

Using Context Provider

import React, { useMemo } from "react";
import { LoroDoc } from "loro-crdt";
import { schema } from "loro-mirror";
import { createLoroContext } from "loro-mirror-react";

// Define your schema
const todoSchema = schema({
    todos: schema.LoroList(
        schema.LoroMap({
            text: schema.String({ required: true }),
            completed: schema.Boolean({ defaultValue: false }),
        }),
        (t) => t.$cid, // stable id from Loro container id
    ),
});

// Create a context
const {
    LoroProvider,
    useLoroContext,
    useLoroState,
    useLoroSelector,
    useLoroAction,
} = createLoroContext(todoSchema);

// Root component
function App() {
    const doc = useMemo(() => new LoroDoc(), []);

    return (
        <LoroProvider doc={doc} initialState={{ todos: [] }}>
            <TodoList />
            <AddTodoForm />
        </LoroProvider>
    );
}

// Todo list component
function TodoList() {
    // Subscribe only to the todos array
    const todos = useLoroSelector((state) => state.todos);

    return (
        <ul>
            {todos.map((todo) => (
                <TodoItem
                    key={todo.$cid /* stable key from Loro container id */}
                    todo={todo}
                />
            ))}
        </ul>
    );
}

// Todo item component
function TodoItem({ todo }) {
    const toggleTodo = useLoroAction((state) => {
        const todoIndex = state.todos.findIndex((t) => t.$cid === todo.$cid); // compare by `$cid`
        if (todoIndex !== -1) {
            state.todos[todoIndex].completed =
                !state.todos[todoIndex].completed;
        }
    });

    return (
        <li>
            <input
                type="checkbox"
                checked={todo.completed}
                onChange={toggleTodo}
            />
            <span>{todo.text}</span>
        </li>
    );
}

API Reference

useLoroStore

Creates and manages a Loro Mirror store.

const { state, setState, store } = useLoroStore({
  doc,
  schema,
  initialState,
  validateUpdates,
  throwOnValidationError,
  debug,
});

Notes on updates:

- `setState` from `useLoroStore` and the setter from `useLoroState` run synchronously; subsequent code can read the updated state immediately.
- `useLoroCallback` and `useLoroAction` return synchronous functions that call `setState` under the hood.

useLoroValue

Subscribes to a specific value from a Loro Mirror store.

const todos = useLoroValue(store, (state) => state.todos);

useLoroCallback

Creates a callback that updates a Loro Mirror store.

const addTodo = useLoroCallback(
    store,
    (state, text) => {
        state.todos.push({ text, completed: false }); // `$cid` is injected from Loro container id
    },
    [
        /* dependencies */
    ],
);

// Usage
addTodo("New todo");

createLoroContext

Creates a context provider and hooks for a Loro Mirror store.

const {
    LoroContext,
    LoroProvider,
    useLoroContext,
    useLoroState,
    useLoroSelector,
    useLoroAction,
} = createLoroContext(schema);

LoroProvider

Provider component for the Loro Mirror context.

<LoroProvider
    doc={loroDoc}
    initialState={initialState}
    validateUpdates={true}
    throwOnValidationError={false}
    debug={false}
>
    {children}
</LoroProvider>

useLoroContext

Hook to access the Loro Mirror store from context.

const store = useLoroContext();

useLoroState

Hook to access and update the full state.

const [state, setState] = useLoroState();

useLoroSelector

Hook to select a specific value from the state.

const todos = useLoroSelector((state) => state.todos);

useLoroAction

Hook to create an action that updates the state.

const addTodo = useLoroAction(
  (state, text) => {
    state.todos.push({ text, completed: false }); // `$cid` comes from Loro container id
  },
  [/* dependencies */]
);

### `$cid` and list keys/selectors

- `$cid` is always available on `LoroMap` state and mirrors the underlying Loro container id.
- Use `$cid` for React `key` and as the list `idSelector` for stable identity across edits and moves: `schema.LoroList(item, x => x.$cid)`.

// Usage
addTodo('New todo');

License

MIT

Keywords

react

FAQs

Package last updated on 22 Dec 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts