rivetkit-client-react

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

RivetKit React Client

RivetKit React客户端

Use this skill when building React apps that connect to Rivet Actors with
@rivetkit/react
.
当你构建通过
@rivetkit/react
连接到Rivet Actors的React应用时,可使用本指南。

First Steps

初步步骤

  1. Install the React client (latest: 2.0.42)
    bash
    npm install @rivetkit/react@2.0.42
  2. Create hooks with
    createRivetKit()
    and connect with
    useActor()
    .
  1. 安装React客户端(最新版本:2.0.42)
    bash
    npm install @rivetkit/react@2.0.42
  2. 使用
    createRivetKit()
    创建hooks,并通过
    useActor()
    建立连接。

Getting Started

快速上手

See the React quickstart guide for getting started.
查看React快速入门指南开始使用。

Install

安装

Minimal Client

最小化客户端

tsx
import { createRivetKit } from "@rivetkit/react";
import type { registry } from "./registry";

const { useActor } = createRivetKit<typeof registry>({
  endpoint: "https://my-namespace:pk_...@api.rivet.dev",
});

function Counter() {
  const { connection, connStatus } = useActor({ name: "counter", key: ["my-counter"] });

  if (connStatus !== "connected" || !connection) return <div>Connecting...</div>;
  return <button onClick={() => connection.increment(1)}>+</button>;
}
ts
import { actor, setup } from "rivetkit";

export const counter = actor({
  state: { count: 0 },
  actions: {
    increment: (c, x: number) => {
      c.state.count += x;
      c.broadcast("newCount", c.state.count);
      return c.state.count;
    },
  },
});

export const registry = setup({
  use: { counter },
});
tsx
import { createRivetKit } from "@rivetkit/react";
import type { registry } from "./registry";

const { useActor } = createRivetKit<typeof registry>({
  endpoint: "https://my-namespace:pk_...@api.rivet.dev",
});

function Counter() {
  const { connection, connStatus } = useActor({ name: "counter", key: ["my-counter"] });

  if (connStatus !== "connected" || !connection) return <div>Connecting...</div>;
  return <button onClick={() => connection.increment(1)}>+</button>;
}
ts
import { actor, setup } from "rivetkit";

export const counter = actor({
  state: { count: 0 },
  actions: {
    increment: (c, x: number) => {
      c.state.count += x;
      c.broadcast("newCount", c.state.count);
      return c.state.count;
    },
  },
});

export const registry = setup({
  use: { counter },
});

Stateless vs Stateful

无状态与有状态

tsx
import { createRivetKit } from "@rivetkit/react";

const { useActor } = createRivetKit();

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

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

  return <button onClick={increment}>+</button>;
}
tsx
// Stateless: use createClient for one-off calls (SSR or utilities)
import { createClient } from "rivetkit/client";

const client = createClient();
await client.counter.getOrCreate(["my-counter"]).increment(1);
tsx
import { createRivetKit } from "@rivetkit/react";

const { useActor } = createRivetKit();

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

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

  return <button onClick={increment}>+</button>;
}
tsx
// 无状态:使用createClient进行一次性调用(SSR或工具类场景)
import { createClient } from "rivetkit/client";

const client = createClient();
await client.counter.getOrCreate(["my-counter"]).increment(1);

Getting Actors

获取Actors实例

tsx
import { createRivetKit } from "@rivetkit/react";
import { createClient } from "rivetkit/client";

const { useActor } = createRivetKit();

function ChatRoom() {
  const room = useActor({ name: "chatRoom", key: ["room-42"] });
  return <div>{room.connStatus}</div>;
}

// For get/getOrCreate/create/getForId, use createClient
const client = createClient();
const handle = client.chatRoom.getOrCreate(["room-42"]);
const existing = client.chatRoom.get(["room-42"]);
const created = await client.game.create(["game-1"], { input: { mode: "ranked" } });
const byId = client.chatRoom.getForId("actor-id");
const resolvedId = await handle.resolve();
tsx
import { createRivetKit } from "@rivetkit/react";
import { createClient } from "rivetkit/client";

const { useActor } = createRivetKit();

function ChatRoom() {
  const room = useActor({ name: "chatRoom", key: ["room-42"] });
  return <div>{room.connStatus}</div>;
}

// 对于get/getOrCreate/create/getForId操作,使用createClient
const client = createClient();
const handle = client.chatRoom.getOrCreate(["room-42"]);
const existing = client.chatRoom.get(["room-42"]);
const created = await client.game.create(["game-1"], { input: { mode: "ranked" } });
const byId = client.chatRoom.getForId("actor-id");
const resolvedId = await handle.resolve();

Connection Parameters

连接参数

tsx
import { createRivetKit } from "@rivetkit/react";

const { useActor } = createRivetKit();

function Chat() {
  const chat = useActor({
    name: "chatRoom",
    key: ["general"],
    params: { authToken: "jwt-token-here" },
  });

  return <div>{chat.connStatus}</div>;
}
tsx
import { createRivetKit } from "@rivetkit/react";

const { useActor } = createRivetKit();

function Chat() {
  const chat = useActor({
    name: "chatRoom",
    key: ["general"],
    params: { authToken: "jwt-token-here" },
  });

  return <div>{chat.connStatus}</div>;
}

Subscribing to Events

订阅事件

tsx
import { createRivetKit } from "@rivetkit/react";

const { useActor } = createRivetKit();

function Chat() {
  const chat = useActor({ name: "chatRoom", key: ["general"] });

  chat.useEvent("message", (msg) => {
    console.log("message:", msg);
  });

  return null;
}
tsx
import { createRivetKit } from "@rivetkit/react";

const { useActor } = createRivetKit();

function Chat() {
  const chat = useActor({ name: "chatRoom", key: ["general"] });

  chat.useEvent("message", (msg) => {
    console.log("message:", msg);
  });

  return null;
}

Connection Lifecycle

连接生命周期

tsx
import { createRivetKit } from "@rivetkit/react";

const { useActor } = createRivetKit();

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

  if (actor.connStatus === "connected") {
    console.log("connected");
  }

  if (actor.error) {
    console.error(actor.error);
  }

  return null;
}
tsx
import { createRivetKit } from "@rivetkit/react";

const { useActor } = createRivetKit();

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

  if (actor.connStatus === "connected") {
    console.log("connected");
  }

  if (actor.error) {
    console.error(actor.error);
  }

  return null;
}

Low-Level HTTP & WebSocket

底层HTTP与WebSocket

Use the JavaScript client for raw HTTP and WebSocket access:
tsx
import { createClient } from "rivetkit/client";

const client = createClient();
const handle = client.chatRoom.getOrCreate(["general"]);

const response = await handle.fetch("history");
const history = await response.json();

const ws = await handle.websocket("stream");
ws.addEventListener("message", (event) => {
  console.log("message:", event.data);
});
ws.send("hello");
使用JavaScript客户端获取原始HTTP和WebSocket访问权限:
tsx
import { createClient } from "rivetkit/client";

const client = createClient();
const handle = client.chatRoom.getOrCreate(["general"]);

const response = await handle.fetch("history");
const history = await response.json();

const ws = await handle.websocket("stream");
ws.addEventListener("message", (event) => {
  console.log("message:", event.data);
});
ws.send("hello");

Calling from Backend

从后端调用

Use the JavaScript client on your backend (Node.js/Bun). See the JavaScript client docs.
可在后端(Node.js/Bun)使用JavaScript客户端。查看JavaScript客户端文档

Error Handling

错误处理

tsx
import { ActorError } from "rivetkit/client";
import { createRivetKit } from "@rivetkit/react";

const { useActor } = createRivetKit();

function Profile() {
  const actor = useActor({ name: "user", key: ["user-123"] });

  const updateUsername = async () => {
    try {
      await actor.connection?.updateUsername("ab");
    } catch (error) {
      if (error instanceof ActorError) {
        console.log(error.code, error.metadata);
      }
    }
  };

  return <button onClick={updateUsername}>Update</button>;
}
tsx
import { ActorError } from "rivetkit/client";
import { createRivetKit } from "@rivetkit/react";

const { useActor } = createRivetKit();

function Profile() {
  const actor = useActor({ name: "user", key: ["user-123"] });

  const updateUsername = async () => {
    try {
      await actor.connection?.updateUsername("ab");
    } catch (error) {
      if (error instanceof ActorError) {
        console.log(error.code, error.metadata);
      }
    }
  };

  return <button onClick={updateUsername}>Update</button>;
}

Concepts

核心概念

Keys

Keys(唯一标识)

Keys uniquely identify actor instances. Use compound keys (arrays) for hierarchical addressing:
tsx
import { createRivetKit } from "@rivetkit/react";
import type { registry } from "./registry";

const { useActor } = createRivetKit<typeof registry>();

function ChatRoom() {
  const room = useActor({ name: "chatRoom", key: ["org-acme", "general"] });
  return <div>{room.connStatus}</div>;
}
ts
import { actor, setup } from "rivetkit";

export const chatRoom = actor({
  state: { messages: [] as string[] },
  actions: {
    getRoomInfo: (c) => ({ org: c.key[0], room: c.key[1] }),
  },
});

export const registry = setup({
  use: { chatRoom },
});
Don't build keys with string interpolation like
"org:${userId}"
when
userId
contains user data. Use arrays instead to prevent key injection attacks.
Keys用于唯一标识actor实例。可使用复合keys(数组)进行层级寻址:
tsx
import { createRivetKit } from "@rivetkit/react";
import type { registry } from "./registry";

const { useActor } = createRivetKit<typeof registry>();

function ChatRoom() {
  const room = useActor({ name: "chatRoom", key: ["org-acme", "general"] });
  return <div>{room.connStatus}</div>;
}
ts
import { actor, setup } from "rivetkit";

export const chatRoom = actor({
  state: { messages: [] as string[] },
  actions: {
    getRoomInfo: (c) => ({ org: c.key[0], room: c.key[1] }),
  },
});

export const registry = setup({
  use: { chatRoom },
});
当userId包含用户数据时,不要使用字符串拼接(如
"org:${userId}"
)来构建keys,应使用数组形式以防止key注入攻击。

Environment Variables

环境变量

createRivetKit()
(and the underlying
createClient()
instance) automatically read:
  • RIVET_ENDPOINT
  • RIVET_NAMESPACE
  • RIVET_TOKEN
  • RIVET_RUNNER
Defaults to
window.location.origin + "/api/rivet"
in the browser or
http://127.0.0.1:6420
on the server when unset.
createRivetKit()
(及其底层的
createClient()
实例)会自动读取以下环境变量:
  • RIVET_ENDPOINT
  • RIVET_NAMESPACE
  • RIVET_TOKEN
  • RIVET_RUNNER
在浏览器环境中未设置时,默认值为
window.location.origin + "/api/rivet"
;在服务器环境中未设置时,默认值为
http://127.0.0.1:6420

Endpoint Format

端点格式

Endpoints support URL auth syntax:
https://namespace:token@api.rivet.dev
You can also pass the endpoint without auth and provide
RIVET_NAMESPACE
and
RIVET_TOKEN
separately. For serverless deployments, use your app's
/api/rivet
URL. See Endpoints for details.
端点支持URL认证语法:
https://namespace:token@api.rivet.dev
你也可以传递不含认证信息的端点,单独提供
RIVET_NAMESPACE
RIVET_TOKEN
。对于无服务器部署,使用应用的
/api/rivet
URL。查看端点文档了解详情。

API Reference

API参考

Need More Than the Client?

需要更多客户端之外的内容?

If you need more about Rivet Actors, registries, or server-side RivetKit, add the main skill:
bash
npx skills add rivet-dev/skills
Then use the
rivetkit
skill for backend guidance.
如果你需要了解更多关于Rivet Actors、registries或服务端RivetKit的内容,添加主技能包:
bash
npx skills add rivet-dev/skills
然后使用
rivetkit
技能获取后端相关指南。