React

Zero has built-in support for React. Here's what basic usage looks like.

Setup

Use the ZeroProvider component to setup Zero. It takes care of creating and destroying Zero instances reactively:

import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import { ZeroProvider } from "@rocicorp/zero/react";
import { schema } from "./schema.ts";
import {useSession} from "my-session-provider";

const session = useSession();
const {userID, auth} = session;
const server = import.meta.env.VITE_PUBLIC_SERVER;

createRoot(document.getElementById("root")!).render(
  <ZeroProvider {...{ userID, auth, server, schema }}>
    <App />
  </ZeroProvider>
);

You can also pass a Zero instance to the ZeroProvider if you want to control the lifecycle of the Zero instance yourself:

// ZeroProvider just sets up the context, it doesn't manage
// the lifecycle of the Zero instance.
<ZeroProvider zero={zero}>
  <App />
</ZeroProvider>

Usage

Use the useZero to get the current Zero instance, then useQuery to run queries:

import { useQuery, useZero } from "@rocicorp/zero/react";
import { Schema } from "./schema";

function Posts() {
  const z = useZero<Schema>();
  const [posts] = useQuery(z.query.posts
    .where("status", "draft")
    .related("comments"));

  return <>
    {posts.map((p) => (
      <div key={p.id}>
        {p.title} ({p.comments.length} comments)
      </div>
    ))}
  </>;
}

Suspense

The useSuspenseQuery hook is exactly like useQuery, except it support React Suspense.

const [issues] = useSuspenseQuery(issueQuery, {
  suspendUntil: 'complete', // 'partial' or 'complete'
});

Use the suspendUntil parameter to control how long to suspend for. The value complete suspends until authoritative results from the server are received. The partial value suspends until any non-empty data is received, or for a empty result that is complete.

Examples

See the sample directory for more complete React examples.