@unhingged/vizu-react
v0.1.21
Published
React bindings for @unhingged/vizu-core — VizuProvider, useVizu, useComments, useVizuUser, useVizuEvent.
Downloads
2,643
Maintainers
Readme
@vizu/react
React bindings for @vizu/core. Drop a provider in your tree, use hooks to read comments / set identity / register actions.
npm install @vizu/core @vizu/reactUse it
'use client';
import { VizuProvider, useVizu, useComments, useVizuUser, useVizuEvent, useVizuAction } from '@vizu/react';
export default function App() {
return (
<VizuProvider options={{
namespace: 'my-site',
pageVersion: 'v1',
shortcut: 'mod+shift+e',
user: { name: 'Anonymous' },
startEnabled: true,
}}>
<YourPage />
</VizuProvider>
);
}
function YourPage() {
// 1. Read current user (re-renders on setUser)
const [user, setUser] = useVizuUser();
// 2. Hydrate identity from your auth/session
useEffect(() => {
setUser({ id: session.userId, name: session.name, avatarUrl: session.avatar });
}, [session]);
// 3. Read live comments (re-renders on add/remove/clear/set)
const comments = useComments();
// 4. Listen to events — persist to your backend
useVizuEvent('comment:added', ({ comment }) => {
fetch('/api/comments', { method: 'POST', body: JSON.stringify(comment) });
});
// 5. Register a pill action
useVizuAction({
id: 'send-to-api',
label: 'Send to API',
variant: 'primary',
onClick: (ctx) => fetch('/api/iterate', {
method: 'POST',
body: JSON.stringify({ comments: ctx.comments, pageHtml: ctx.pageHtml }),
}),
visibleWhen: ({ commentsCount }) => commentsCount > 0,
});
// 6. Imperative access
const vizu = useVizu();
useEffect(() => {
// Pre-load comments from your backend
fetch(`/api/comments?ns=my-site`).then(r => r.json()).then(c => vizu.setComments(c, { persist: false }));
}, [vizu]);
return <div>Your page content…</div>;
}What you get
<VizuProvider>— mounts a single Vizu instance for the subtree (lazy, destroyed on unmount)useVizu()— the instance itself for imperative calls (vizu.enable(),vizu.clearAll(), etc.)useComments()— subscribes to all comment-list events, returnsVizuComment[]useVizuUser()—[user, setUser]tuple, re-renders onuser:changeduseVizuEvent('event', handler)— subscribe to any Vizu event for the component lifetimeuseVizuAction({...})— register an action while mounted; auto-removed on unmount
Storage defaults
Programmatic mode defaults to in-memory storage. Provide options.storage if you want persistence:
<VizuProvider options={{ storage: 'local' }}>...
<VizuProvider options={{ storage: myCustomAdapter }}>...Or skip storage entirely and own it in your effects — listen to comment:added and POST to your API.
Next.js (App Router)
VizuProvider is a client component (it uses refs + effects). Put it inside a layout that opts in:
// app/(commentable)/layout.tsx
'use client';
import { VizuProvider } from '@vizu/react';
export default function Layout({ children }) {
return <VizuProvider options={{ namespace: 'my-app' }}>{children}</VizuProvider>;
}Page-level usage stays as Server Components; only the provider and the components that call its hooks need the 'use client' directive.
