Skip to content

React Setup

This guide covers setting up SyncRabbit in a React application (Vite, Create React App, etc.).

Installation

bash
npm install @syncrabbit/react

Running the Engine

Unlike Next.js, React apps need to run the SyncRabbit engine separately.

Run the engine in a separate terminal:

bash
# Terminal 1: Start the engine
DATABASE_URL=postgresql://user:password@host:5432/database npx syncrabbit dev

# Terminal 2: Run your React app
npm run dev

Initialize the database first (one-time):

bash
DATABASE_URL=postgresql://user:password@host:5432/database npx syncrabbit init

Option B: Node SDK (Custom Backend)

If you have an Express, Fastify, or other Node.js backend, you can manage the engine programmatically:

typescript
// server.ts
import express from "express";
import { ensureEngine } from "@syncrabbit/node";

const app = express();

async function start() {
  // Start the SyncRabbit engine
  const wsUrl = await ensureEngine({
    databaseUrl: process.env.DATABASE_URL,
  });
  console.log(`SyncRabbit ready at ${wsUrl}`);

  app.listen(3000, () => {
    console.log("Server running on port 3000");
  });
}

start();

Setup

Add Provider

Wrap your app with the SyncRabbitProvider:

tsx
// main.tsx or App.tsx
import { SyncRabbitProvider } from "@syncrabbit/react";

function App() {
  return (
    <SyncRabbitProvider url="ws://localhost:4500/ws">
      <YourApp />
    </SyncRabbitProvider>
  );
}

TIP

The default URL is ws://localhost:4500/ws. You can omit the url prop if using the default.

Usage

useTable - Subscribe to a Table

tsx
import { useTable } from "@syncrabbit/react";

interface User {
  id: number;
  name: string;
  email: string;
}

function UserList() {
  const { data: users, loading, error } = useTable<User>("users", {
    initialFetch: async () => {
      const res = await fetch("/api/users");
      return res.json();
    },
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

useWatch - React to Changes

tsx
import { useWatch } from "@syncrabbit/react";
import { useState, useEffect } from "react";

function UserList() {
  const [users, setUsers] = useState([]);

  const fetchUsers = async () => {
    const res = await fetch("/api/users");
    setUsers(await res.json());
  };

  useEffect(() => {
    fetchUsers();
  }, []);

  // Refetch when users table changes
  useWatch("users", fetchUsers);

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

Watch Multiple Tables

tsx
useWatch(["orders", "order_items"], () => {
  refetchOrders();
});

Detailed Change Info

tsx
useWatch(
  "users",
  (info) => {
    console.log(info.operation); // "insert" | "update" | "delete" | "truncate"
    console.log(info.row); // The affected row data
  },
  { detailed: true }
);

useMutation - Write with Instant Invalidation

tsx
import { useMutation } from "@syncrabbit/react";

function CreateUser() {
  const { mutate, loading, error } = useMutation({
    tables: ["users"],
    mutationFn: async (data: { name: string; email: string }) => {
      const res = await fetch("/api/users", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data),
      });
      return res.json();
    },
  });

  // After mutate() succeeds, all useWatch callbacks for "users" fire immediately
  const handleCreate = () => {
    mutate({ name: "Alice", email: "alice@example.com" });
  };

  return (
    <button onClick={handleCreate} disabled={loading}>
      Create User
    </button>
  );
}

Released under the MIT License.