Sign In
Frontend & Clients

React

Learn how to create real-time, stateful React applications with Rivet's actor model. The React integration provides intuitive hooks for managing actor connections and real-time updates.

Basic Usage

Installation

Install the RivetKit React package:

npm install @rivetkit/actor @rivetkit/react

Use in Components

Make sure you have a running Rivet actor server to connect to. You can follow the Node.js & Bun Quickstart to set up a simple actor server.

Connect to actors and listen for real-time updates:

frontend/App.tsx
import { useState } from "react";
import { useActor } from "./rivetkit";

function App() {
  const [count, setCount] = useState(0);
  const [counterName, setCounterName] = useState("my-counter");

  // Connect to the counter actor
  const counter = useActor({
    name: "counter",
    key: [counterName],
  });

  // Listen for real-time count updates
  counter.useEvent("countChanged", (newCount: number) => {
    setCount(newCount);
  });

  const increment = async () => {
    await counter.connection?.increment(1);
  };

  return (
    <div style={{ padding: "2rem" }}>
      <h1>Rivet Counter</h1>
      <h2>Count: {count}</h2>
      
      <div style={{ marginBottom: "1rem" }}>
        <label>
          Counter Name:
          <input
            type="text"
            value={counterName}
            onChange={(e) => setCounterName(e.target.value)}
            style={{ marginLeft: "0.5rem", padding: "0.25rem" }}
          />
        </label>
      </div>

      <button onClick={increment} disabled={!counter.isConnected}>
        Increment
      </button>

      <div style={{ marginTop: "1rem", fontSize: "0.9rem", color: "#666" }}>
        <p>Status: {counter.isConnected ? "Connected" : "Disconnected"}</p>
      </div>
    </div>
  );
}

export default App;

API Reference

createRivetKit(client, options?)

Creates the Rivet hooks for React integration.

React
import { createClient, createRivetKit } from "@rivetkit/react";

const client = createClient<typeof registry>("http://localhost:8080");
const { useActor } = createRivetKit(client);

Parameters

  • client: The Rivet client created with createClient
  • options: Optional configuration object

Returns

An object containing:

  • useActor: Hook for connecting to actors

useActor(options)

Hook that connects to an actor and manages the connection lifecycle.

React
const actor = useActor({
  name: "actorName",
  key: ["actor-id"],
  params: { userId: "123" },
  enabled: true
});

Parameters

  • options: Object containing:
    • name: The name of the actor type (string)
    • key: Array of strings identifying the specific actor instance
    • params: Optional parameters passed to the actor connection
    • createWithInput: Optional input to pass to the actor on creation
    • createInRegion: Optional region to create the actor in if does not exist
    • enabled: Optional boolean to conditionally enable/disable the connection (default: true)
    • enabled: Optional boolean to conditionally enable/disable the connection (default: true)

Returns

Actor object with the following properties:

  • connection: The actor connection for calling actions, or null if not connected
  • isConnected: Boolean indicating if the actor is connected
  • state: Current actor state (if available)
  • useEvent(eventName, handler): Method to subscribe to actor events

actor.useEvent(eventName, handler)

Subscribe to events emitted by the actor.

React
const actor = useActor({ name: "counter", key: ["my-counter"] });

actor.useEvent("countChanged", (newCount: number) => {
  console.log("Count changed:", newCount);
});

Parameters

  • eventName: The name of the event to listen for (string)
  • handler: Function called when the event is emitted

Lifecycle

The event subscription is automatically managed:

  • Subscribes when the actor connects
  • Cleans up when the component unmounts or actor disconnects
  • Re-subscribes on reconnection

Advanced Patterns

Multiple Actors

Connect to multiple actors in a single component:

React
function Dashboard() {
  const userProfile = useActor({
    name: "userProfile", 
    key: ["user-123"]
  });
  
  const notifications = useActor({
    name: "notifications",
    key: ["user-123"]
  });

  userProfile.useEvent("profileUpdated", (profile) => {
    console.log("Profile updated:", profile);
  });

  notifications.useEvent("newNotification", (notification) => {
    console.log("New notification:", notification);
  });

  return (
    <div>
      <UserProfile actor={userProfile} />
      <NotificationList actor={notifications} />
    </div>
  );
}

Conditional Connections

Control when actors connect using the enabled option:

React
function ConditionalActor() {
  const [enabled, setEnabled] = useState(false);

  const counter = useActor({
    name: "counter",
    key: ["conditional"],
    enabled: enabled // Only connect when enabled
  });

  return (
    <div>
      <button onClick={() => setEnabled(!enabled)}>
        {enabled ? "Disconnect" : "Connect"}
      </button>
      {enabled && counter.isConnected && (
        <p>Count: {counter.state?.count}</p>
      )}
    </div>
  );
}

Real-time Collaboration

Build collaborative features with multiple event listeners:

React
function CollaborativeEditor() {
  const [content, setContent] = useState("");
  const [cursors, setCursors] = useState<Record<string, Position>>({});
  
  const document = useActor({
    name: "document",
    key: ["doc-123"],
    params: { userId: getCurrentUserId() }
  });

  // Listen for content changes
  document.useEvent("contentChanged", (newContent) => {
    setContent(newContent);
  });

  // Listen for cursor movements
  document.useEvent("cursorMoved", ({ userId, position }) => {
    setCursors(prev => ({ ...prev, [userId]: position }));
  });

  // Listen for user join/leave
  document.useEvent("userJoined", ({ userId }) => {
    console.log(`${userId} joined the document`);
  });

  document.useEvent("userLeft", ({ userId }) => {
    setCursors(prev => {
      const { [userId]: _, ...rest } = prev;
      return rest;
    });
  });

  const updateContent = async (newContent: string) => {
    await document.connection?.updateContent(newContent);
  };

  return (
    <div>
      <Editor 
        content={content}
        cursors={cursors}
        onChange={updateContent}
      />
    </div>
  );
}

Authentication

Connect authenticated actors in React:

React
function AuthenticatedApp() {
	const [authToken, setAuthToken] = useState<string | null>(null);

	const counter = useActor({
		name: "protectedCounter",
		key: ["user-counter"],
		params: {
			authToken: authToken
		},
		enabled: !!authToken // Only connect when authenticated
	});

	const login = async () => {
		const token = await authenticateUser();
		setAuthToken(token);
	};

	if (!authToken) {
		return <button onClick={login}>Login</button>;
	}

	return (
		<div>
			<h1>Authenticated Counter</h1>
			{/* ... rest of authenticated UI */}
		</div>
	);
}

Learn more about authentication.

Suggest changes to this page