{"id":13632239,"url":"https://github.com/getditto/react-ditto","last_synced_at":"2026-04-04T01:44:31.986Z","repository":{"id":40414220,"uuid":"393528715","full_name":"getditto/react-ditto","owner":"getditto","description":"React wrappers for Ditto for easy integration using both components or hooks","archived":false,"fork":false,"pushed_at":"2026-03-20T15:29:17.000Z","size":3837,"stargazers_count":41,"open_issues_count":3,"forks_count":2,"subscribers_count":29,"default_branch":"master","last_synced_at":"2026-04-04T01:44:29.069Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://getditto.github.io/react-ditto/","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/getditto.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-08-06T23:30:11.000Z","updated_at":"2026-03-20T15:27:31.000Z","dependencies_parsed_at":"2024-01-22T01:14:10.368Z","dependency_job_id":"dcdd0e2f-a38f-4c6e-a178-83f32e36e80a","html_url":"https://github.com/getditto/react-ditto","commit_stats":{"total_commits":127,"total_committers":7,"mean_commits":"18.142857142857142","dds":0.6929133858267716,"last_synced_commit":"4bd908b045816ccd74641199c512347e2566c0db"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/getditto/react-ditto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getditto%2Freact-ditto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getditto%2Freact-ditto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getditto%2Freact-ditto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getditto%2Freact-ditto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/getditto","download_url":"https://codeload.github.com/getditto/react-ditto/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getditto%2Freact-ditto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31384845,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T01:22:39.193Z","status":"ssl_error","status_checked_at":"2026-04-04T01:22:33.970Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T22:02:57.220Z","updated_at":"2026-04-04T01:44:31.954Z","avatar_url":"https://github.com/getditto.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# React Wrapper Library for Ditto\n\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)\n![example workflow](https://github.com/getditto/react-ditto/actions/workflows/ci.yml/badge.svg)\n\nThis is a React wrapper library for [Ditto](https://www.ditto.live).\n\nCurrently, this project works in web browsers, Node.JS and Electron environments. This project will soon have support for React Native environments. Please reach out to us using the email address below if you are interested in support for React Native.\n\nIf you have questions about this project or require any assistance, please get in touch via [contact@ditto.live](contact@ditto.live).\n\n## Installation\n\n1. Install this library with npm or yarn:\n\n```\nnpm install @dittolive/ditto @dittolive/react-ditto\n```\n\nor with yarn\n\n```\nyarn add @dittolive/ditto @dittolive/react-ditto\n```\n\n2. At the top level of your react app, wrap it with any of the context providers provided: `DittoProvider` or `DittoLazyProvider`, like so:\n\n```tsx\n\u003cDittoProvider setup={createDittoInstance}\u003e\n  {({ loading, error }) =\u003e {\n    if (loading) return \u003cspan\u003eLoading Ditto...\u003c/span\u003e\n    if (error)\n      return (\n        \u003cspan\u003eThere was an error loading Ditto. Error: {error.toString()}\u003c/span\u003e\n      )\n    return \u003cApp /\u003e\n  }}\n\u003c/DittoProvider\u003e\n```\n\nAt this point you're ready to build your Ditto app using all of the helper hooks provided by the library. If you want to learn more, read the following sections to learn how to choose between `DittoProvider` and `DittoLazyProvider`, how to create Ditto identities, and how to use the hooks provided by this library.\n\n## Choosing a Provider\n\nThe Ditto React library includes two different context providers which you can use in order to initialize the Ditto context for your app: `DittoProvider` and `DittoLazyProvider`.\n\n`DittoProvider` should be used when the set of Ditto instances that will be used by your app are known beforehand. This is by far the simplest use case where an app uses a single or a few Ditto instances well known beforehand, that can be initialized statically when the app is bootstrapped. In all other cases, the `DittoLazyProvider` can be used to lazily create Ditto instances, such that instances will only be created if a child of the Ditto provider requires them and the instance doesn't exist inside of the provider.\n\nThe API for both providers is very similar and only differs for the `setup` prop, which returns `Ditto | Ditto[]` for `DittoProvider` and `Promise\u003cDitto | null\u003e` for `DittoLazyProvider`.\n\nIt is important to highlight that choosing one provider or the other has no effect on the remaining hooks provided by the library. All hooks can be used in the same way, regardless of the type of provider that you choose to configure inside your app.\n\n### DittoProvider Example\n\n```tsx\nconst createDittoInstance = () =\u003e {\n  const ditto = new Ditto(createIdentity(), 'some-path')\n  ditto.startSync()\n  return ditto\n}\n\n;\u003cDittoProvider setup={createDittoInstance}\u003e\n  {({ loading, error }) =\u003e {\n    if (loading) return \u003cspan\u003eLoading Ditto...\u003c/span\u003e\n    if (error)\n      return (\n        \u003cspan\u003eThere was an error loading Ditto. Error: {error.toString()}\u003c/span\u003e\n      )\n    return \u003cApp /\u003e\n  }}\n\u003c/DittoProvider\u003e\n```\n\n### DittoLazyProvider Example\n\n```tsx\nconst createDittoInstance = async (path) =\u003e {\n  let identity\n  if (path === 'path-1') {\n    identity = await getIdentityForPath1()\n  } else if (path === 'path-2') {\n    identity = await getIdentityForPath2()\n  }\n\n  if (identity) {\n    const ditto = new Ditto(createIdentity(), path)\n    ditto.startSync()\n    return ditto\n  } else {\n    return Promise.resolve(null)\n  }\n}\n\n;\u003cDittoLazyProvider setup={createDittoInstance}\u003e\n  {({ loading, error }) =\u003e {\n    if (loading) return \u003cspan\u003eLoading Ditto...\u003c/span\u003e\n    if (error)\n      return (\n        \u003cspan\u003eThere was an error loading Ditto. Error: {error.toString()}\u003c/span\u003e\n      )\n    return \u003cApp /\u003e\n  }}\n\u003c/DittoLazyProvider\u003e\n```\n\n## Creating Identities\n\nDitto instances are created by providing an `Identity` object to the Ditto constructor. Identities can be of several different types,\nand can be created manually as JS objects, or using the identity hooks (`useOfflinePlaygroundIdentity`, `useOnlineIdentity`, `useOnlinePlaygroundIdentity`), which also makes it easier to configure authentication for your\napps:\n\n### Offline Identities\n\n```ts\nconst { create } = useOfflinePlaygroundIdentity()\n\nconst createDittoInstance = (forPath: string) =\u003e {\n  // Example of how to create an offline playground instance\n  const dittoPlaygroundIdentity = new Ditto(\n    create({\n      // If you're using the Ditto cloud, this ID should be the app ID shown on your app settings page on the portal.\n      appID: uuidv4(),\n      siteID: 123,\n    }),\n    forPath,\n  )\n  dittoPlaygroundIdentity.startSync()\n  return dittoPlaygroundIdentity\n}\n```\n\n### Online Identities\n\n```ts\nconst { create, getAuthenticationRequired, getTokenExpiresInSeconds } =\n  useOnlineIdentity()\n\nconst createDittoInstance = (forPath: string) =\u003e {\n  // Example of how to create an online instance with authentication enabled\n  const dittoOnline = new Ditto(\n    create(\n      {\n        // If you're using the Ditto cloud, this ID should be the app ID shown on your app settings page on the portal.\n        appID: uuidv4(),\n        enableDittoCloudSync: true,\n      },\n      forPath,\n    ),\n    forPath,\n  )\n  dittoOnline.startSync()\n  return dittoOnline\n}\n```\n\n```ts\nconst { create } = useOnlinePlaygroundIdentity()\n\nconst createDittoInstance = (forPath: string) =\u003e {\n  // Example of how to create an online playground instance\n  const dittoOnline = new Ditto(\n    create({\n      // If you're using the Ditto cloud, this ID should be the app ID shown on your app settings page on the portal.\n      appID: uuidv4(),\n      // If you're using the Ditto cloud, this token should be the Online Playground Authentication Token shown on your app settings page on the portal.\n      token: 'my-token',\n    }),\n    forPath,\n  )\n  dittoOnline.startSync()\n  return dittoOnline\n}\n```\n\nYou can find more information on working with online apps [here](#working-with-online-apps)\n\n## Quick Start with `vite`\n\nThis is a quick guide on using Ditto with `vite` builds.\n\n1. Install this library with npm or yarn\n\n```\nnpm install @dittolive/ditto @dittolive/react-ditto\n```\n\nor with yarn\n\n```\nyarn add @dittolive/ditto @dittolive/react-ditto\n```\n\n2. In `./src/index.js`, or `./src/index.tsx` if you're using typescript, setup Ditto with the `DittoProvider` like so:\n\n```tsx\n// ... other imports from vite above\nimport { Ditto } from '@dittolive/ditto'\nimport {\n  DittoProvider,\n  useOnlinePlaygroundIdentity,\n} from '@dittolive/react-ditto'\n\n/**\n * This configuration is optional for web browser-based react applications. This\n * tells the `DittoProvider` where it should load the .wasm file. If no path is\n * provided (ie. initOptions is undefined), the wasm will be loaded from our\n * CDN. If you enable this, make sure to serve the `ditto.wasm` file with the\n * correct MIME type and CORS headers. See\n * https://www.npmjs.com/package/@dittolive/ditto#browser-environments for\n * details.\n **/\nconst initOptions = {\n  webAssemblyModule: '/ditto.wasm',\n}\n\n/** Example of a React root component setting up a single ditto instance that uses a development connection */\nconst RootComponent = () =\u003e {\n  const { create } = useOnlinePlaygroundIdentity()\n\n  return (\n    \u003cDittoProvider\n      setup={async () =\u003e {\n        const ditto = new Ditto(\n          create({\n            // Create an app on https://portal.ditto.live/ and follow the\n            // instructions to get your token. Replace the placeholders below\n            // with your app id and token.\n            appID: 'your-app-id',\n            token: 'your-online-playground-token',\n          }),\n          'testing',\n        )\n        await ditto.disableSyncWithV3()\n        ditto.startSync()\n        return ditto\n      }}\n      /* initOptions={initOptions} */\n    \u003e\n      {({ loading, error }) =\u003e {\n        if (loading) return \u003cp\u003eLoading\u003c/p\u003e\n        if (error) return \u003cp\u003e{error.message}\u003c/p\u003e\n        return \u003cApp /\u003e\n      }}\n    \u003c/DittoProvider\u003e\n  )\n}\n\nconst root = ReactDOM.createRoot(document.getElementById('root'))\nroot.render(\n  \u003cReact.StrictMode\u003e\n    \u003cRootComponent /\u003e\n  \u003c/React.StrictMode\u003e,\n)\n```\n\n3. In your `App` component, you can now use hooks like `usePendingCursorOperation` or `usePendingIDSpecificOperation` to get your documents like so:\n\n```tsx\nimport { usePendingCursorOperation, useMutations } from '@dittolive/react-ditto'\n\nexport default function App() {\n  const { documents } = usePendingCursorOperation({\n    collection: 'tasks',\n  })\n\n  const { removeByID, upsert } = useMutations({ collection: 'tasks' })\n\n  return (\n    \u003c\u003e\n      \u003cbutton onClick={() =\u003e upsert({ value: { text: 'Hello' } })}\u003e\n        Add Task\n      \u003c/button\u003e\n      \u003cul\u003e\n        {documents.map((doc) =\u003e (\n          \u003cli key={doc._id}\u003e\n            {JSON.stringify(doc.value)}\n            \u003cbutton onClick={() =\u003e removeByID({ _id: doc.id })}\u003eremove\u003c/button\u003e\n          \u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n    \u003c/\u003e\n  )\n}\n```\n\nAlternatively, you can also choose to go with the lazy variants of these hooks (`useLazyPendingCursorOperation` and `useLazyPendingIDSpecificOperation`), in order to launch queries on the data store as a response to a user event:\n\n```tsx\nimport { useLazyPendingCursorOperation } from '@dittolive/react-ditto'\n\nexport default function App() {\n  const { documents, exec } = useLazyPendingCursorOperation()\n\n  if (!documents?.length) {\n    return (\n      \u003cbutton onClick={() =\u003e exec({ collection: 'tasks' })}\u003e\n        Click to load!\n      \u003c/button\u003e\n    )\n  }\n\n  return (\n    \u003cul\u003e\n      {documents.map((doc) =\u003e (\n        \u003cli key={doc._id}\u003e{JSON.stringify(doc.value)}\u003c/li\u003e\n      ))}\n    \u003c/ul\u003e\n  )\n}\n```\n\n## Working with Online apps\n\nUsing the [Portal](http://portal.ditto.live) you can create apps that sync to the cloud. If you're just getting started with Ditto and want to experiment without authentication, you may use the `useOnlinePlaygroundIdentity` hook to create an `onlinePlayground` identity type. This **should not** be used in production environments. Otherwise, online apps must be created with an `onlineWithAuthentication` identity type, for which the `useOnlineIdentity` hook can be used. The `useOnlineIdentity` hook helps you create online Ditto instances that sync with the cloud, following these steps:\n\n```tsx\n/** Example of a React root component setting up a single ditto instance that uses a development connection */\nimport { useEffect } from 'react'\n\nconst RootComponent = () =\u003e {\n  const { create, getAuthenticationRequired, getTokenExpiresInSeconds } =\n    useOnlineIdentity()\n\n  return (\n    \u003c\u003e\n      \u003cDittoProvider\n        setup={() =\u003e {\n          const ditto = new Ditto(\n            create(\n              { appID: 'your-app-id', path: '/my-online-path' },\n              '/my-online-path',\n            ),\n          )\n          ditto.startSync()\n          return ditto\n        }}\n        /*initOptions={initOptions} */\n      \u003e\n        {({ loading, error, ditto }) =\u003e {\n          if (loading) return \u003cp\u003eLoading\u003c/p\u003e\n          if (error) return \u003cp\u003e{error.message}\u003c/p\u003e\n          return \u003cApp /\u003e\n        }}\n      \u003c/DittoProvider\u003e\n    \u003c/\u003e\n  )\n}\n\nconst App = () =\u003e {\n  const ditto = useDitto()\n\n  useEffect(() =\u003e {\n    if (ditto) {\n      ditto.auth\n        .loginWithToken('token', 'provider')\n        .then(() =\u003e console.log('Login successful'))\n    }\n  }, [ditto])\n\n  return \u003cdiv\u003eHello world!\u003c/div\u003e\n}\n```\n\nFor Online apps, the `useOnlineIdentity` hook returns the following set of properties that can be used to manage authentication for your app:\n\n- `create`: Creates an `onlineWithAuthentication` object preconfigured such that the hook can manage the authentication flow using the exposed `authenticate` function.\n- `getAuthenticationRequired`: Is a function that takes in the app path for which to check the authentication required state, and will return true if your Ditto instance is requiring the current user to authenticate with the app. You can configure authentication webhooks on the [Portal](http://portal.ditto.live), from your app settings area, in order to provide your own set of validation services for your app.\n- `getTokenExpiresInSeconds`: Is a function that takes in the app path for which to check the token expiry second, and returns the number of seconds in which your current token expires if this has been reported by the Ditto SDK.\n\n## Building this library and running tests\n\n- **Building:** run `npm run build` or `yarn build`.\n- **Run Tests:** run `npm test` or `yarn test`\n- **Generating Documentation Website Files** run `npm run docs:generate`\n\n## Running example apps.\n\nEach example project is in its own directory underneath the [./examples](./examples) directory.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetditto%2Freact-ditto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgetditto%2Freact-ditto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetditto%2Freact-ditto/lists"}