Package Exports
- @zanzojs/react
Readme
@zanzojs/react
React bindings for ZanzoJS.
Checking permissions on the frontend needs to be instant. You don't want to make an HTTP request every time a button renders, and you shouldn't ship heavy graph traversal logic to the browser.
@zanzojs/react solves this by consuming a "Flat Snapshot" generated by your backend. It evaluates permissions strictly synchronously in O(1) time limits.
Installation
This package requires @zanzojs/core and react as peer dependencies.
pnpm add @zanzojs/core @zanzojs/reactStep-by-Step Guide
1. Generate the Snapshot (Backend)
When a user logs into your app, or loads a Server Component in Next.js, you calculate their entire permission graph once by providing their tuples to the ZanzoEngine and generating a snapshot.
import { createZanzoSnapshot, ZanzoEngine } from '@zanzojs/core';
import { schema } from './zanzo.config';
import { db, zanzoTuples } from './db';
import { like } from 'drizzle-orm';
export async function getUserSnapshot(userId: string) {
// Fetch all tuples related to this user from the DB
const userTuples = await db.select().from(zanzoTuples).where(like(zanzoTuples.subject, `User:${userId}%`));
// Create a fresh engine per request — never reuse a shared instance
const requestEngine = new ZanzoEngine(schema);
requestEngine.addTuples(userTuples);
// Extract a flattened JSON dictionary
return createZanzoSnapshot(requestEngine, `User:${userId}`);
}2. The Context Provider (Frontend)
Wrap your application (or the authenticated portion of it) with <ZanzoProvider>. It expects the snapshot object you just generated.
'use client';
import { ZanzoProvider } from '@zanzojs/react';
import type { CompiledPermissions } from '@zanzojs/core';
interface AppLayoutProps {
children: React.ReactNode;
snapshot: CompiledPermissions;
}
export default function AppLayout({ children, snapshot }: AppLayoutProps) {
return (
<ZanzoProvider snapshot={snapshot}>
{children}
</ZanzoProvider>
);
}3. The useZanzo Hook (Client Components)
Any child component within the provider can now instantly check access using the custom hook.
'use client';
import { useZanzo } from '@zanzojs/react';
export function EditDocumentButton({ documentId }: { documentId: string }) {
const { can } = useZanzo();
// Instant dictionary lookup!
// No lag, no re-renders, no network requests.
if (!can('write', `Document:${documentId}`)) {
return <span className="text-gray-500">Read Only View</span>;
}
return <button className="bg-blue-500 text-white">Edit Document</button>;
}Behavior Notes
By intentionally offloading the graph logic to the server, these React tools rely on point-in-time snapshots. If a user's permissions change deeply in the backend, the React app won't know until you fetch and provide a new snapshot to the ZanzoProvider. We recommend re-fetching snapshots on critical path navigations.
Documentation
For backend compilation instructions, refer to the ZanzoJS Monorepo.