@dittolive/react-ditto

中文文档
1.0.1发布于 2026/06/10ISCTypeScriptESM + CJS近 30 天下载 2.4万

React wrappers for Ditto

原始使用文档
文档目录13 节
  1. Installation
  2. Choosing a Provider
  3. DittoProvider Example
  4. DittoLazyProvider Example
  5. Opening Ditto instances
  6. Offline / peer-to-peer
  7. Online (connected to a Ditto server / Big Peer)
  8. Querying with useQuery
  9. Mutating and on-demand queries with useExecuteQuery
  10. Quick Start with vite
  11. Working with online apps
  12. Building this library and running tests
  13. Running example apps

React Wrapper Library for Ditto

TypeScript example workflow

This is a React wrapper library for Ditto.

Currently, this project works in web browsers, Node.JS and Electron environments.

If you have questions about this project or require any assistance, please get in touch via [email protected].

Ditto SDK v5

This library targets the Ditto v5 SDK (@dittolive/ditto@^5.0.0) and uses DQL (Ditto Query Language) exclusively. The v4 query-builder hooks (usePendingCursorOperation, useMutations, etc.) and the identity hooks (useOnlinePlaygroundIdentity, etc.) have been removed. See the Ditto v5 migration guide for the underlying SDK changes.

Installation

Install this library alongside the Ditto SDK with npm or yarn:

npm install @dittolive/ditto @dittolive/react-ditto
yarn add @dittolive/ditto @dittolive/react-ditto

At the top level of your React app, wrap it with one of the context providers, DittoProvider or DittoLazyProvider:

<DittoProvider setup={createDittoInstance}>
  {({ loading, error }) => {
    if (loading) return <span>Loading Ditto...</span>
    if (error)
      return (
        <span>There was an error loading Ditto. Error: {error.toString()}</span>
      )
    return <App />
  }}
</DittoProvider>

At this point you're ready to build your Ditto app using the hooks provided by the library. Read on to learn how to choose between DittoProvider and DittoLazyProvider, how to open Ditto instances with the v5 API, and how to use the useQuery and useExecuteQuery hooks.

Choosing a Provider

The library includes two context providers that initialize the Ditto context for your app: DittoProvider and DittoLazyProvider.

DittoProvider should be used when the set of Ditto instances used by your app is known beforehand and can be created when the app is bootstrapped. In all other cases, DittoLazyProvider can be used to lazily create Ditto instances on demand when a child of the provider first requires one.

The API for both providers is identical except for the setup prop, which returns Ditto | Ditto[] | Promise<Ditto | Ditto[]> for DittoProvider and Promise<Ditto | null> for DittoLazyProvider.

Choosing one provider over the other has no effect on the remaining hooks — they are used in exactly the same way regardless of provider.

DittoProvider Example

import { Ditto, DittoConfig } from '@dittolive/ditto'

const createDittoInstance = async () => {
  const ditto = await Ditto.open(
    new DittoConfig('my-database-id', { mode: 'smallPeersOnly' }, 'some-path'),
  )
  ditto.sync.start()
  return ditto
}

;<DittoProvider setup={createDittoInstance}>
  {({ loading, error }) => {
    if (loading) return <span>Loading Ditto...</span>
    if (error)
      return (
        <span>There was an error loading Ditto. Error: {error.toString()}</span>
      )
    return <App />
  }}
</DittoProvider>

DittoLazyProvider Example

import { Ditto, DittoConfig } from '@dittolive/ditto'

const createDittoInstance = async (path: string) => {
  const ditto = await Ditto.open(
    new DittoConfig('my-database-id', { mode: 'smallPeersOnly' }, path),
  )
  ditto.sync.start()
  return ditto
}

;<DittoLazyProvider setup={createDittoInstance}>
  {({ loading, error }) => {
    if (loading) return <span>Loading Ditto...</span>
    if (error)
      return (
        <span>There was an error loading Ditto. Error: {error.toString()}</span>
      )
    return <App />
  }}
</DittoLazyProvider>

When multiple instances are registered, hooks select one via the persistenceDirectory option, which matches the persistence directory you set on the instance's DittoConfig. When omitted, the first registered instance is used.

Opening Ditto instances

In v5, a Ditto instance is opened with Ditto.open(config) (async) or Ditto.openSync(config), where the config is a DittoConfig describing the database ID, the connection mode, and an optional persistence directory.

Offline / peer-to-peer

import { Ditto, DittoConfig } from '@dittolive/ditto'

const ditto = await Ditto.open(
  new DittoConfig('my-database-id', { mode: 'smallPeersOnly' }, '/path'),
)
ditto.sync.start()

Online (connected to a Ditto server / Big Peer)

Server connections require an authentication expiration handler to be set before sync is started — ditto.sync.start() throws otherwise. Copy the whole connection URL from the Ditto portal (Connect via SDK → URL); do not build it from the database ID.

import { Authenticator, Ditto, DittoConfig } from '@dittolive/ditto'

const ditto = await Ditto.open(
  new DittoConfig(
    'my-database-id',
    { mode: 'server', url: 'REPLACE_ME_WITH_YOUR_URL' },
    '/path',
  ),
)

await ditto.auth.setExpirationHandler(async (ditto) => {
  await ditto.auth.login('your-token', Authenticator.DEVELOPMENT_PROVIDER)
})

ditto.sync.start()

Querying with useQuery

useQuery continuously fetches the results of a non-mutating DQL query by registering a store observer and (unless localOnly is set) a sync subscription. It returns the current items, loading state, and any error.

import { useQuery } from '@dittolive/react-ditto'

type Task = { _id: string; body: string; isCompleted: boolean }

export default function App() {
  const { items, isLoading, error } = useQuery<Task>(
    'SELECT * FROM tasks WHERE isCompleted = :isCompleted',
    { queryArguments: { isCompleted: false } },
  )

  if (isLoading) return <p>Loading…</p>
  if (error) return <p>Error: {String(error)}</p>

  return (
    <ul>
      {items.map((task) => (
        <li key={task.value._id}>{task.value.body}</li>
      ))}
    </ul>
  )
}

Mutating and on-demand queries with useExecuteQuery

useExecuteQuery returns an execution function that runs a DQL query on demand. Use it for mutations (insert/update/delete) and ad-hoc queries triggered by user actions. It does not set up a sync subscription, so pair mutations with a useQuery for the same collection if you want them synced and observed.

import { useExecuteQuery } from '@dittolive/react-ditto'

export default function AddTask() {
  const [insertTask] = useExecuteQuery<void, { value: { body: string } }>(
    'INSERT INTO tasks DOCUMENTS (:value)',
  )

  return (
    <button onClick={() => insertTask({ value: { body: 'Buy milk' } })}>
      Add Task
    </button>
  )
}

Query arguments can be supplied when setting up the hook and/or when calling the execution function; when both are provided they are shallow-merged, with the execution function's arguments taking precedence.

Quick Start with vite

  1. Install the library:
npm install @dittolive/ditto @dittolive/react-ditto
  1. In ./src/index.tsx, set up Ditto with the DittoProvider:
// ... other imports from vite above
import { Ditto, DittoConfig } from '@dittolive/ditto'
import { DittoProvider } from '@dittolive/react-ditto'

/**
 * This configuration is optional for web browser-based React applications. It
 * tells the `DittoProvider` where to load the .wasm file. If no path is provided
 * (ie. initOptions is undefined), the wasm is loaded from our CDN. If you enable
 * this, make sure to serve `ditto.wasm` with the correct MIME type and CORS
 * headers. See
 * https://www.npmjs.com/package/@dittolive/ditto#browser-environments for
 * details.
 **/
const initOptions = {
  webAssemblyModule: '/ditto.wasm',
}

const RootComponent = () => (
  <DittoProvider
    setup={async () => {
      // Create a database at https://portal.ditto.live/ and copy its database
      // ID and connection URL from the settings page.
      const ditto = await Ditto.open(
        new DittoConfig(
          'your-database-id',
          { mode: 'smallPeersOnly' },
          'testing',
        ),
      )
      ditto.sync.start()
      return ditto
    }}
    /* initOptions={initOptions} */
  >
    {({ loading, error }) => {
      if (loading) return <p>Loading</p>
      if (error) return <p>{error.message}</p>
      return <App />
    }}
  </DittoProvider>
)

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
  <React.StrictMode>
    <RootComponent />
  </React.StrictMode>,
)
  1. In your App component, use useQuery to observe documents and useExecuteQuery to mutate them — see the examples above and the full vite example app.

Working with online apps

Using the Portal you can create apps that sync with a Ditto server (Big Peer). Configure the instance with a { mode: 'server', url } connection and authenticate through ditto.auth:

  • Set an expiration handler with ditto.auth.setExpirationHandler(handler). The handler receives the Ditto instance and is invoked whenever (re)authentication is required.
  • Inside the handler, call ditto.auth.login(token, provider). Use Authenticator.DEVELOPMENT_PROVIDER for playground/development tokens, or your own provider string when you have configured authentication webhooks on the Portal.
  • The expiration handler must be set before calling ditto.sync.start() for server connections.

The current authentication state is available via ditto.auth.status ({ isAuthenticated, userID }).

Building this library and running tests

  • Building: run npm run build.
  • Type-check: run npm run types.
  • Lint: run npm run lint.
  • Run tests: run npm test. The suite runs in headless Chrome via Karma and exercises the real Ditto WASM build.

Running example apps

Each example project is in its own directory underneath the ./examples directory.

版本与发布记录

@dittolive/react-ditto 共发布 25 个版本,首次发布于 2021/10/04;过去 12 个月发布了 2 个版本。

版本发布日期距今
1.0.1latest2026/06/105 个月前
1.0.02026/06/105 个月前
0.11.22024/12/021.9 年前
0.11.12024/05/232 年前
0.11.02023/03/223 年前
0.11.0-alpha.02023/01/243 年前

其他发布通道:alpha → 0.9.0-alpha.0。

关于 @dittolive/react-ditto 的常见问题

@dittolive/react-ditto 是什么?

React wrappers for Ditto

如何安装 @dittolive/react-ditto?

在项目目录运行 npm install @dittolive/react-ditto,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=16.0.0)、react-dom(>=16.0.0)、@dittolive/ditto(^5.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@dittolive/react-ditto 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@dittolive/react-ditto 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@dittolive/react-ditto 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@dittolive/react-ditto 可以商用吗?

@dittolive/react-ditto 使用 ISC 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@dittolive/react-ditto 的下载量有多少?

根据 npm 官方下载统计,@dittolive/react-ditto 在 2026/10/13 – 2026/11/11 这 30 天内被下载 23,871 次,日均约 796 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@dittolive/react-ditto 还在维护吗?

最新版本 1.0.1 发布于 2026/06/10(5 个月前);至今共发布 25 个版本,其中过去 12 个月发布了 2 个;首次发布于 2021/10/04。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。