diff --git a/site/public/llms-full.txt b/site/public/llms-full.txt index f436e98e1a..327316992d 100644 --- a/site/public/llms-full.txt +++ b/site/public/llms-full.txt @@ -2927,6 +2927,7 @@ const registry = setup(, Start a server to run your actors: ```ts } +// Run server with default configuration (port 8080) registry.runServer(); ``` @@ -3783,36 +3784,7 @@ function CollaborativeEditor() ); } ``` -## Client Connection Options - -### Basic Client Setup - -Create a type-safe client to connect to your backend: - -```ts client.ts -// Create typed client -const client = createClient("http://localhost:8080"); - -// Use the counter actor directly -const counter = client.counter.getOrCreate(["my-counter"]); - -// Call actions -const count = await counter.increment(3); -console.log("New count:", count); - -// Get current state -const currentCount = await counter.getCount(); -console.log("Current count:", currentCount); - -// Listen to real-time events -const connection = counter.connect(); -connection.on("countChanged", (newCount) => ); - -// Increment through connection -await connection.increment(1); -``` - -### React Integration +## React Integration Use the React hooks for seamless integration: @@ -3862,9 +3834,7 @@ const config = , Update your server to use environment-based configuration: ```ts server.ts -const = registry.createServer(config.rivetkit); - -// ... rest of server setup +registry.runServer(config.rivetkit); ``` ### Frontend Environment Variables diff --git a/site/src/content/docs/actors/quickstart/react.mdx b/site/src/content/docs/actors/quickstart/react.mdx index 8ec8d697db..f845c4cf13 100644 --- a/site/src/content/docs/actors/quickstart/react.mdx +++ b/site/src/content/docs/actors/quickstart/react.mdx @@ -21,6 +21,7 @@ Create your actor registry on the backend: import { actor, setup } from "@rivetkit/actor"; export const counter = actor({ + onAuth: () => {}, // Skip authentication (can be configured later) state: { count: 0 }, actions: { increment: (c, amount: number = 1) => { @@ -45,6 +46,8 @@ Start a server to run your actors: ```ts {{"title":"backend/server.ts"}} import { registry } from "./registry"; + +// Run server with default configuration (port 8080) registry.runServer(); ``` diff --git a/site/src/content/docs/clients/react.mdx b/site/src/content/docs/clients/react.mdx index 78f0396d24..f961d6d141 100644 --- a/site/src/content/docs/clients/react.mdx +++ b/site/src/content/docs/clients/react.mdx @@ -1,7 +1,5 @@ # React -Build real-time React applications with Rivet Actors - 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. ## Installation @@ -18,11 +16,11 @@ npm install @rivetkit/actor @rivetkit/react First, set up your actor registry (typically in your backend): -```typescript -// backend/registry.ts +```typescript {{"title":"backend/registry.ts"}} import { actor, setup } from "@rivetkit/actor"; export const counter = actor({ + onAuth: () => {}, // Skip authentication (can be configured later) state: { count: 0 }, actions: { increment: (c, amount: number = 1) => { @@ -40,11 +38,21 @@ export const registry = setup({ ``` + +Start a server to run your actors: + +```typescript {{"title":"backend/server.ts"}} +import { registry } from "./registry"; + +// Run server with default configuration (port 8080) +registry.runServer(); +``` + + Create a typed client and Rivet hooks: -```tsx -// src/rivetkit.ts +```tsx {{"title":"frontend/App.tsx"}} import { createClient, createRivetKit } from "@rivetkit/react"; import type { registry } from "../backend/registry"; @@ -56,8 +64,7 @@ export const { useActor } = createRivetKit(client); Connect to actors and listen for real-time updates: -```tsx -// src/App.tsx +```tsx {{"title":"frontend/App.tsx"}} import { useState } from "react"; import { useActor } from "./rivetkit"; @@ -251,128 +258,6 @@ function ConditionalActor() { } ``` -### Authentication - -Pass authentication parameters to actors: - -```tsx -function AuthenticatedChat() { - const [authToken] = useAuthToken(); // Your auth hook - - const chatRoom = useActor({ - name: "chatRoom", - key: ["general"], - params: { - authToken, - userId: getCurrentUserId() - } - }); - - chatRoom.useEvent("messageReceived", (message) => { - console.log("New message:", message); - }); - - const sendMessage = async (text: string) => { - await chatRoom.connection?.sendMessage(text); - }; - - return ( -
- {/* Chat UI */} -
- ); -} -``` - -### Error Handling - -Handle connection errors gracefully: - -```tsx -function ResilientCounter() { - const [error, setError] = useState(null); - - const counter = useActor({ - name: "counter", - key: ["resilient"] - }); - - counter.useEvent("error", (err) => { - setError(err.message); - // Clear error after 5 seconds - setTimeout(() => setError(null), 5000); - }); - - counter.useEvent("connected", () => { - setError(null); - }); - - return ( -
- {error && ( -
- Error: {error} -
- )} -
- Status: {counter.isConnected ? "Connected" : "Disconnected"} -
- {/* Rest of component */} -
- ); -} -``` - -### Custom Hooks - -Create reusable custom hooks for common patterns: - -```tsx -// Custom hook for a counter with persistent state -function useCounter(counterId: string) { - const [count, setCount] = useState(0); - - const counter = useActor({ - name: "counter", - key: [counterId] - }); - - counter.useEvent("countChanged", setCount); - - const increment = useCallback(async (amount = 1) => { - await counter.connection?.increment(amount); - }, [counter.connection]); - - const reset = useCallback(async () => { - await counter.connection?.reset(); - }, [counter.connection]); - - return { - count, - increment, - reset, - isConnected: counter.isConnected - }; -} - -// Usage -function App() { - const { count, increment, reset, isConnected } = useCounter("my-counter"); - - return ( -
-

Count: {count}

- - -
- ); -} -``` - ### Real-time Collaboration Build collaborative features with multiple event listeners: @@ -426,175 +311,7 @@ function CollaborativeEditor() { } ``` -## Client Connection Options - -### Basic Client Setup - -Create a type-safe client to connect to your backend: - -```ts client.ts -import { createClient } from "@rivetkit/actor/client"; -import type { registry } from "./registry"; - -// Create typed client -const client = createClient("http://localhost:8080"); - -// Use the counter actor directly -const counter = client.counter.getOrCreate(["my-counter"]); - -// Call actions -const count = await counter.increment(3); -console.log("New count:", count); - -// Get current state -const currentCount = await counter.getCount(); -console.log("Current count:", currentCount); - -// Listen to real-time events -const connection = counter.connect(); -connection.on("countChanged", (newCount) => { - console.log("Count changed:", newCount); -}); - -// Increment through connection -await connection.increment(1); -``` - -### React Integration - -Use the React hooks for seamless integration: - -```tsx -import { useState } from "react"; -import { createClient, createRivetKit } from "@rivetkit/react"; -import type { registry } from "./registry"; - -const client = createClient("http://localhost:8080"); -const { useActor } = createRivetKit(client); - -function App() { - const [count, setCount] = useState(0); - const [counterName, setCounterName] = useState("test-counter"); - - const counter = useActor({ - name: "counter", - key: [counterName], - }); - - counter.useEvent("countChanged", (newCount: number) => setCount(newCount)); - - const increment = async () => { - await counter.connection?.increment(1); - }; - - return ( -
-

Counter: {count}

- setCounterName(e.target.value)} - placeholder="Counter name" - /> - -
- ); -} -``` - -## Environment Configuration - -### Development vs Production - -Create environment-specific configurations: - -```ts config.ts -const isDev = process.env.NODE_ENV !== "production"; - -export const config = { - port: parseInt(process.env.PORT || "8080"), - rivetkit: { - driver: isDev - ? { - topology: "standalone" as const, - actor: { type: "memory" as const }, - manager: { type: "memory" as const }, - } - : { - topology: "partition" as const, - actor: { type: "redis" as const, url: process.env.REDIS_URL! }, - manager: { type: "redis" as const, url: process.env.REDIS_URL! }, - }, - }, -}; -``` - -### Backend Configuration - -Update your server to use environment-based configuration: - -```ts server.ts -import { registry } from "./registry"; -import { config } from "./config"; - -const { client, serve } = registry.createServer(config.rivetkit); - -// ... rest of server setup -``` - -### Frontend Environment Variables - -Configure your frontend for different environments: - -```ts .env.local -VITE_API_URL=http://localhost:8080 -VITE_WS_URL=ws://localhost:8080 -``` - -```ts config/client.ts -const API_URL = import.meta.env.VITE_API_URL || "http://localhost:8080"; - -export const client = createClient(API_URL); -``` - -## Authentication Integration - -### Protected Actors - -Add authentication to secure your actors: - -```ts registry.ts -import { actor, setup } from "@rivetkit/actor"; - -export const protectedCounter = actor({ - onAuth: async (opts) => { - const token = opts.params.authToken || opts.req.headers.get("Authorization"); - - if (!token) { - throw new Error("Authentication required"); - } - - // Validate token and return user data - const user = await validateJWT(token); - return { userId: user.id, role: user.role }; - }, - - state: { count: 0 }, - - actions: { - increment: (c, amount: number = 1) => { - // Access auth data via c.conn.auth - const { userId } = c.conn.auth; - - c.state.count += amount; - c.broadcast("countChanged", { count: c.state.count, userId }); - return c.state.count; - }, - }, -}); -``` - -### React Authentication +### Authentication Connect authenticated actors in React: @@ -631,12 +348,3 @@ function AuthenticatedApp() { Learn more about [authentication](/docs/general/authentication). -## Best Practices - -1. **Use Custom Hooks**: Extract actor logic into reusable custom hooks -2. **Handle Loading States**: Always account for the initial loading state -3. **Error Boundaries**: Implement error boundaries around actor components -4. **Conditional Connections**: Use the `enabled` prop to control when actors connect -5. **Event Cleanup**: Event listeners are automatically cleaned up, but be mindful of heavy operations in handlers -6. **State Management**: Combine with React state for local UI state that doesn't need to be shared -