React Hooks
vuer-rtc provides React hooks for seamless integration with React applications.
See Operations for the complete reference of operation types you can use with these hooks.
Installation
The hooks are available from the /hooks subpath:
import {
GraphProvider,
useGraph,
useNode,
useNodeProperty,
useRootKey,
useGraphActions,
useUndoRedoShortcuts
} from '@vuer-ai/vuer-rtc/hooks';GraphProvider
Wrap your app with GraphProvider to provide the graph context:
function App() {
return (
<GraphProvider sessionId="my-session" onSend={sendToServer}>
<Scene />
</GraphProvider>
);
}Props
| Prop | Type | Description |
|---|---|---|
sessionId | string | Unique session identifier |
onSend | (msg: CRDTMessage) => void | Callback when a message is ready to send |
useGraph
Get the current graph state:
function Scene() {
const graph = useGraph();
return (
<>
{Object.keys(graph.nodes).map(key => (
<Node key={key} nodeKey={key} />
))}
</>
);
}useNode
Subscribe to a specific node by key. Re-renders only when that node changes:
function Node({ nodeKey }: { nodeKey: string }) {
const node = useNode(nodeKey);
if (!node) return null;
return (
<mesh position={node.position}>
<boxGeometry />
</mesh>
);
}useNodeProperty
Subscribe to a specific property of a node. More granular than useNode—only re-renders when that property changes:
function NodePosition({ nodeKey }: { nodeKey: string }) {
const position = useNodeProperty<[number, number, number]>(nodeKey, 'position');
if (!position) return null;
return <mesh position={position}><boxGeometry /></mesh>;
}useRootKey
Subscribe to the root node key. Re-renders only when the root key changes:
function SceneRoot() {
const rootKey = useRootKey();
if (!rootKey) return <p>No scene loaded</p>;
return <Node nodeKey={rootKey} />;
}useGraphActions
Get actions to modify the graph:
function Node({ nodeKey }: { nodeKey: string }) {
const node = useNode(nodeKey);
const { edit, commit, undo, redo } = useGraphActions();
const onDrag = (delta: [number, number, number]) => {
edit({ otype: 'vector3.add', key: nodeKey, path: 'position', value: delta });
};
const onDragEnd = () => {
commit(`Move ${node?.name}`);
};
if (!node) return null;
return <mesh position={node.position} onDrag={onDrag} onDragEnd={onDragEnd} />;
}Available Actions
| Action | Signature | Description |
|---|---|---|
edit | (op: Operation) => void | Add operation to edit buffer (uncommitted) |
commit | (description?: string) => void | Commit edits as a single message |
cancelEdits | () => void | Discard uncommitted edits |
undo | () => void | Undo last committed message |
redo | () => void | Redo last undone message |
receive | (msg: CRDTMessage) => void | Process incoming remote message |
useUndoRedoShortcuts
Enables keyboard shortcuts for undo/redo:
- Cmd/Ctrl+Z: Undo
- Cmd/Ctrl+Shift+Z: Redo
function App() {
useUndoRedoShortcuts();
return <Scene />;
}Full Example
import {
GraphProvider,
useGraph,
useNode,
useGraphActions,
useUndoRedoShortcuts
} from '@vuer-ai/vuer-rtc/hooks';
function App() {
const wsRef = useRef<WebSocket | null>(null);
const handleSend = (msg: CRDTMessage) => {
wsRef.current?.send(JSON.stringify(msg));
};
return (
<GraphProvider sessionId="user-123" onSend={handleSend}>
<SceneWithShortcuts />
</GraphProvider>
);
}
function SceneWithShortcuts() {
useUndoRedoShortcuts(); // Cmd/Ctrl+Z to undo, Cmd/Ctrl+Shift+Z to redo
return (
<>
<Canvas>
<Scene />
</Canvas>
<UndoRedoButtons />
</>
);
}
function Scene() {
const graph = useGraph();
const { receive } = useGraphActions();
// Handle incoming messages
useEffect(() => {
const ws = new WebSocket('wss://server/room');
ws.onmessage = (e) => receive(JSON.parse(e.data));
return () => ws.close();
}, [receive]);
return (
<>
{Object.keys(graph.nodes)
.filter(k => !graph.nodes[k].deletedAt)
.map(key => <Node key={key} nodeKey={key} />)}
</>
);
}
function UndoRedoButtons() {
const { undo, redo } = useGraphActions();
return (
<div>
<button onClick={undo}>Undo</button>
<button onClick={redo}>Redo</button>
</div>
);
}Next: See the Complete Integration Guide for end-to-end examples of building collaborative applications.