> ## Documentation Index
> Fetch the complete documentation index at: https://chahine.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# React

> React hooks for Meridian CRDTs.

Install the React package alongside the core SDK:

```bash theme={null}
npm install meridian-react meridian-sdk effect react
# or
pnpm add meridian-react meridian-sdk effect react
# or
bun add meridian-react meridian-sdk effect react
```

## Setup

Create a client and pass it to `MeridianProvider`:

```tsx theme={null}
import { Effect } from "effect";
import { MeridianClient } from "meridian-sdk";
import { MeridianProvider } from "meridian-react";

const client = await Effect.runPromise(
  MeridianClient.create({
    url: "ws://localhost:3000",
    namespace: "my-app",
    token: process.env.MERIDIAN_TOKEN!,
  })
);

function App() {
  return (
    <MeridianProvider client={client}>
      <YourApp />
    </MeridianProvider>
  );
}
```

The provider closes the client automatically on unmount. All hooks in the tree share the same connection.

## Hooks

### `useGCounter`

```tsx theme={null}
const { value, increment } = useGCounter("gc:page-views");

<button onClick={() => increment()}>+1</button>
<span>{value}</span>
```

### `usePNCounter`

```tsx theme={null}
const { value, increment, decrement } = usePNCounter("pn:votes");
```

### `useORSet`

Define the schema **outside the component** so its reference is stable:

```tsx theme={null}
import { Schema } from "effect";

const Task = Schema.Struct({ id: Schema.String, title: Schema.String });

function TaskList() {
  const { elements, add, remove } = useORSet("or:tasks", Task);
}
```

### `useLwwRegister`

```tsx theme={null}
const TitleSchema = Schema.String;

function Title() {
  const { value, set } = useLwwRegister("lw:doc-title", TitleSchema);
}
```

### `usePresence`

Define the schema outside the component. Pass `data` to enable auto-heartbeat:

```tsx theme={null}
const CursorSchema = Schema.Struct({ x: Schema.Number, y: Schema.Number });

function Cursors() {
  const { online } = usePresence("pr:cursors", {
    schema: CursorSchema,
    data: { x: mouseX, y: mouseY },
    ttlMs: 5_000,
  });

  return online.map((entry) => (
    <Cursor key={entry.clientId} x={entry.data.x} y={entry.data.y} />
  ));
}
```

If `data` is omitted, the hook subscribes without sending a heartbeat (observe-only).

### `useAwareness`

Ephemeral pub/sub for cursors, selections, and real-time UI state. Updates are fanned out in real time but **not** persisted.

Define the schema **outside the component** for a stable reference:

```tsx theme={null}
import { Schema } from "effect";

const CursorSchema = Schema.Struct({ x: Schema.Number, y: Schema.Number });

function Canvas() {
  const { peers, update, clear } = useAwareness("cursors", CursorSchema);

  return (
    <div
      onMouseMove={(e) => update({ x: e.clientX, y: e.clientY })}
      onMouseLeave={() => clear()}
    >
      {peers.map((entry) => (
        <Cursor key={entry.clientId} x={entry.data.x} y={entry.data.y} />
      ))}
    </div>
  );
}
```

`peers` excludes the current client. For an accurate visitor count, combine with `usePresence`:

```tsx theme={null}
const { peers } = useAwareness("cursors", CursorSchema);
const { online } = usePresence("visitors", { data: {}, ttlMs: 15_000 });

// online.length = exact number of connected clients (including self)
```

See [Awareness](https://chahine.mintlify.site/sdk/crdts/awareness.md) for full API reference.

### `useCRDTMap`

```tsx theme={null}
const { value, lwwSet, incrementCounter } = useCRDTMap("doc:meta");

lwwSet("theme", "dark");
incrementCounter("views");
```

### `usePendingOpCount`

Returns the number of operations buffered locally, waiting to be sent on reconnect. Use it to build a "syncing" indicator:

```tsx theme={null}
import { usePendingOpCount } from "meridian-react";

function SyncIndicator() {
  const pending = usePendingOpCount();
  if (pending === 0) return null;
  return <span>{pending} change{pending > 1 ? "s" : ""} pending...</span>;
}
```

The count is non-zero while disconnected with pending writes, and drops to zero once the connection is restored and all ops are flushed.

### `useMeridianClient`

Access the underlying `MeridianClient` directly:

```tsx theme={null}
import { useMeridianClient } from "meridian-react";

function DebugPanel() {
  const client = useMeridianClient();
  return <pre>{JSON.stringify(client.claims)}</pre>;
}
```

## Requirements

* React 19+
* `meridian-sdk` 0.3+


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.