{"id":13880938,"url":"https://github.com/earthstar-project/react-earthstar","last_synced_at":"2025-04-12T05:28:25.438Z","repository":{"id":43210266,"uuid":"296126145","full_name":"earthstar-project/react-earthstar","owner":"earthstar-project","description":"A UI toolkit for making collaborative, offline-first applets for small groups.","archived":false,"fork":false,"pushed_at":"2023-01-02T12:42:08.000Z","size":3560,"stargazers_count":60,"open_issues_count":3,"forks_count":5,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-05-23T00:24:04.866Z","etag":null,"topics":["decentralized","earthstar","react"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/earthstar-project.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-09-16T19:16:33.000Z","updated_at":"2023-07-25T12:38:38.000Z","dependencies_parsed_at":"2023-02-01T02:45:43.204Z","dependency_job_id":null,"html_url":"https://github.com/earthstar-project/react-earthstar","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earthstar-project%2Freact-earthstar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earthstar-project%2Freact-earthstar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earthstar-project%2Freact-earthstar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earthstar-project%2Freact-earthstar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/earthstar-project","download_url":"https://codeload.github.com/earthstar-project/react-earthstar/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248358734,"owners_count":21090420,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["decentralized","earthstar","react"],"created_at":"2024-08-06T08:03:41.071Z","updated_at":"2025-04-12T05:28:25.402Z","avatar_url":"https://github.com/earthstar-project.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# react-earthstar\n\n## What is this?\n\nA library of React hooks and components for usage with\n[Earthstar](https://earthstar-project.org), storage for private, distributed,\noffline-first application.\n\nThis library is just a few small hooks for subscribing to some events in\nEarthstar, with the same API for querying and writing data.\n\nIt's recommended that you check out Earthstar's\n[README](https://github.com/earthstar-project/earthstar) before reading on if\nyou haven't already.\n\n## Getting started\n\nFirst, install `react-earthstar` and `earthstar` as dependencies to your\nproject:\n\n```\nnpm install earthstar react-earthstar\n```\n\nHere's a basic applet which creates a IndexedDB replica for a `+gardening`\nshare, and renders a list of notes using `useReplica`.\n\n```jsx\nimport * as Earthstar from \"earthstar\";\nimport { useReplica } from 'react-earthstar';\n\n// You get the share address and secret from someone else,\n// Or using Earthstar.Crypto.generateShareKeypair()\n\nconst MY_SHARE_ADDRESS =\n  \"+gardening.bhyux4opeug2ieqcy36exrf4qymc56adwll4zeazm42oamxtr7heq\";\n\nconst MY_SHARE_SECRET = \"buaqth6jr5wkksnhdlpfi64cqcnjzfx3r6cssnfqdvitjmfygsk3q\";\n\nconst replica = new Earthstar.Replica({\n  driver: new ReplicaDriverWeb(MY_SHARE_ADDRESS),\n  shareSecret: MY_SHARE_SECRET,\n});\n\nfunction App() {\n  const cache = useReplica(replica);\n\n  // This will update whenever a document with a path starting with '/notes' updates.\n  const notes = cache.queryDocs({\n    filter: {\n      pathStartsWith: \"/notes\",\n      author: \n    },\n  });\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eMy notes\u003c/h1\u003e\n      { notes.map((noteDoc) =\u003e \n        \u003cli\u003enoteDoc.text\u003c/li\u003e\n      )}\n      \n    \u003c/div\u003e\n  );\n}\n```\n\n## Hooks\n\n### `useReplica`\n\nThis is the workhorse of the library, used for querying documents from replicas.\n\n```js\nconst replica = useReplica(myReplica);\n\nconst txtDocs = replica.queryDocs({ filter: { pathEndsWith: \".txt\" } });\n```\n\nThis hook returns an instance of Earthstar's\n[`ReplicaCache` class](https://doc.deno.land/https://deno.land/x/earthstar@v10.0.0-beta.8/mod.ts/~/ReplicaCache),\nwith the exact same API as `Replica` except synchronous.\n\nWhen you query docs the replica keeps track of what was queried for, and only\nupdates React when the results of those queries are updated. This results in a\nbest-of-both-worlds API where we can have the same API as the vanilla Earthstar\nlibrary, and components which only re-render when they need to. Nice!\n\n### `usePeerReplicas`\n\nReturns an updating array of `Replica` for a given `Peer`.\n\n```js\nfunction ReplicaList() {\n  const replicas = usePeerReplicas(myPeer);\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eMy replicas\u003c/h1\u003e\n      \u003cul\u003e\n        {replicas.map((replica) =\u003e \u003cli\u003e{replica.share}\u003c/li\u003e)}\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### `useAuthorSettings`\n\nReturns a getter and setter for the `SharedSettings`' current author setting.\nUses the `SharedSettingsContext`.\n\n```js\nfunction CurrentAuthorAddress() {\n  const [author, setAuthor] = useAuthorSettings();\n\n  return \u003cdiv\u003e{author.address}\u003c/div\u003e;\n}\n```\n\n### `useShareSettings`\n\nReturns the shares + a callback to add a share + a callback to remove a share\nfrom `SharedSettings`' shares setting. Uses the `SharedSettingsContext`.\n\n```js\nfunction KnownShares() {\n  const [shares, addShare, removeShare] = useAuthorSettings();\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eMy shares\u003c/h1\u003e\n      \u003cul\u003e\n        {shares.map((share) =\u003e \u003cli\u003e{share}\u003c/li\u003e)}\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### `useShareSecretSettings`\n\nReturns the secrets + a callback to add a secret + a callback to remove a secret\nfrom `SharedSettings`' share secrets setting. Uses the `SharedSettingsContext`.\n\n```js\nfunction KnownSecrets() {\n  const [secrets, addSecret, removeSecret] = useAuthorSettings();\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eKnown secrets...p\u003c/h1\u003e\n      \u003cul\u003e\n        {Object.keys(secrets).map((share) =\u003e (\n          \u003cli\u003e{share} {secrets[\"share\"] ? \"✓\" : \"???\"}\u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### `useServerSettings`\n\nReturns the server + a callback to add a server + a callback to remove a server\nfrom `SharedSettings`' servers setting. Uses the `SharedSettingsContext`.\n\n```js\nfunction KnownShares() {\n  const [servers, addServer, removeServer] = useAuthorSettings();\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eMy servers\u003c/h1\u003e\n      \u003cul\u003e\n        {servers.map((share) =\u003e \u003cli\u003e{server}\u003c/li\u003e)}\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n## Components\n\n### `\u003cSharedSettingsContext.Provider\u003e`\n\nIf you're going to use any of the settings hooks, you should provide a single\ninstance of `SharedSettings` as a context for them:\n\n```js\nconst settings = new Earthstar.SharedSettings();\n\nfunction App() {\n  return (\n    \u003cSharedSettings.Provider value={settings}\u003e\n      // Components which use useAuthorSettings, useShareSettings etc.\n      \u003cTheRestOfTheApp /\u003e\n    \u003c/SharedSettings.Provider\u003e\n  );\n}\n```\n\n### `\u003cShareLabel\u003e`\n\nRenders the human readable portion of a share address, and omits the public key:\ne.g. '+gardening.bhyux4opeug2ieqcy36exrf4qymc56adwll4zeazm42oamxtr7heq' becomes\n'+gardening'. Also renders an identicon next to the address to make it harder\nfor shares to be mistaken for one another. Good for making sure you don't\ndisclose share addresses to people looking over your users' shoulders.\n\n```jsx\n\u003cShareLabel address=\"+potatoes.b34ou9e8\"\u003e\n```\n\nAlso takes an `iconSize` prop (side size in `px`), and a `viewingAuthorSecret`\nprop. The latter prop is used as a salt for generating the identicon, making it\nso that each user has their own identicon for each share, making them harder for\nan attacker to imitate. If available, pass the current user's keypair secret to\nthis prop.\n\n### `\u003cIdentityLabel\u003e`\n\nRenders the shortname portion of an identity's address, omitting the public key,\ne.g. `@cinn.euu8euheuigoe...` just becomes `@cinn`.\n\n```jsx\n\u003cIdentityLabel address=\"@devy.a234gue9Juhxo9eu...\"\u003e\n```\n\nAlso takes an `iconSize` prop (side size in `px`), and a `viewingAuthorSecret`\nprop. The latter prop is used as a salt for generating the identicon, making it\nso that each user has their own identicon for each share, making them harder for\nan attacker to imitate. If available, pass the current user's keypair secret to\nthis prop.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fearthstar-project%2Freact-earthstar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fearthstar-project%2Freact-earthstar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fearthstar-project%2Freact-earthstar/lists"}