{"id":17458106,"url":"https://github.com/pocesar/react-use-comlink","last_synced_at":"2026-02-27T00:31:14.106Z","repository":{"id":57347074,"uuid":"193563823","full_name":"pocesar/react-use-comlink","owner":"pocesar","description":"Three ways to use Comlink web workers through React Hooks (and in a typesafe manner).","archived":false,"fork":false,"pushed_at":"2019-11-03T15:49:14.000Z","size":125,"stargazers_count":50,"open_issues_count":1,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-06T20:49:31.878Z","etag":null,"topics":["async","comlink","hooks","mjs","react","react-hook","react-hooks","reactjs","typescript","umd","web","web-workers","webworker","webworkers","worker"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pocesar.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":"2019-06-24T19:08:56.000Z","updated_at":"2025-06-08T04:46:03.000Z","dependencies_parsed_at":"2022-09-16T04:56:37.916Z","dependency_job_id":null,"html_url":"https://github.com/pocesar/react-use-comlink","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/pocesar/react-use-comlink","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocesar%2Freact-use-comlink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocesar%2Freact-use-comlink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocesar%2Freact-use-comlink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocesar%2Freact-use-comlink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pocesar","download_url":"https://codeload.github.com/pocesar/react-use-comlink/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocesar%2Freact-use-comlink/sbom","scorecard":{"id":739314,"data":{"date":"2025-08-11","repo":{"name":"github.com/pocesar/react-use-comlink","commit":"3868b0c0c1a1e3b93490e0c90401c5ff45b4fe4d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/4 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-22T16:56:25.293Z","repository_id":57347074,"created_at":"2025-08-22T16:56:25.293Z","updated_at":"2025-08-22T16:56:25.293Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29878958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T23:51:21.483Z","status":"ssl_error","status_checked_at":"2026-02-26T23:50:46.793Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["async","comlink","hooks","mjs","react","react-hook","react-hooks","reactjs","typescript","umd","web","web-workers","webworker","webworkers","worker"],"created_at":"2024-10-18T03:54:27.338Z","updated_at":"2026-02-27T00:31:14.087Z","avatar_url":"https://github.com/pocesar.png","language":"TypeScript","readme":"[![NPM](https://nodei.co/npm/react-use-comlink.svg?downloads=true)](https://nodei.co/npm/react-use-comlink/)\n[![TypeScript](https://badges.frapsoft.com/typescript/love/typescript.svg?v=101)](https://github.com/ellerbrock/typescript-badges/)\n\n# react-use-comlink\n\nThree ways to use [Comlink](https://github.com/GoogleChromeLabs/comlink) web workers through React Hooks (and in a typesafe manner).\n\n## Usage\n\n```tsx\n// worker.ts\nimport { expose } from 'comlink'\n\nexport class MyClass {\n  private _counter: number\n\n  constructor(init: number) {\n    this._counter = init\n  }\n\n  get counter() {\n    return this._counter\n  }\n\n  increment(delta = 1) {\n    this._counter += delta\n  }\n}\n\nexpose(MyClass)\n```\n\n```tsx\n// index.ts\nimport React from 'react'\nimport useComlink from 'react-use-comlink'\nimport { WorkerClass } from './worker'\n\nconst App: React.FC\u003c{startAt: number}\u003e = (props) =\u003e {\n  const [state, setState] = React.useState(0)\n\n  const { proxy } = useComlink\u003ctypeof WorkerClass\u003e(\n    () =\u003e new Worker('./worker.ts'),\n    [ props.startAt ] // used to recreate the worker if it change, defaults to []\n  )\n\n  React.useEffect(() =\u003e {\n    (async () =\u003e {\n      // methods, constructors and setters are async\n      const classInstance = await new proxy(0)\n\n      await classInstance.increment(1)\n\n      // even getters are asynchronous, regardless of type\n      setState(await classInstance.counter)\n    })()\n  }, [proxy])\n\n  return (\n    \u003cdiv\u003e{state}\u003c/div\u003e\n  )\n}\n\nReactDOM.render(\n  \u003cApp /\u003e,\n  document.getElementById('root')\n)\n```\n\nAlso notice that the `worker` property is also exposed, so you may use the library directly with workers without having to use Comlink (kinda defeats the purpose, but oh well):\n\n```tsx\nconst App = () =\u003e {\n  const { worker } = useComlink('./worker.js')\n\n  useEffect(() =\u003e {\n    worker.onmessage = (e) =\u003e {\n      /*do stuff*/\n    }\n\n    worker.onerror = (e) =\u003e {\n      /*do stuff*/\n    }\n  }, [worker])\n\n  const callback = useCallback(() =\u003e {\n    worker.postMessage('wow')\n  }, [worker])\n\n  return (\u003cbutton onClick={callback}\u003ePost WOW\u003c/button\u003e)\n}\n```\n\n## API\n\nThe api is pretty straightforward, you have the _in loco_ `useComlink`, the factory counter part `createComlink` and the singleton counter part `createComlinkSingleton`.\n\n### useComlink\u003cT = unknown\u003e(initWorker: Blob | string | () =\u003e Worker | string | Blob, deps: any[]): { proxy\u003cT\u003e, worker }\n\nUse directly inside components. Both object and properties are memoized and can be used as deps.\n\n```tsx\nconst MyComponent: React.FC = () =\u003e {\n  const { proxy, worker } = useComlink(() =\u003e new Worker('./worker.js'), [deps])\n}\n```\n\n### createComlink\u003cT = unknown\u003e(initWorker: () =\u003e Worker | string | Blob, options = {}): () =\u003e { proxy\u003cT\u003e, worker }\n\nCreates a factory version that can spawn multiple workers with the same settings\n\n```tsx\n// outside, just like react-cache, createResource\nconst useNumber = createComlink\u003cnumber\u003e(\n  () =\u003e new Worker('worker.js')\n)\n\nconst MyComponent: React.FC = () =\u003e {\n  const { proxy, worker } = useNumber() // call like a hook\n\n  useEffect(() =\u003e {\n    (async () =\u003e {\n      const number = await proxy\n      // use number\n    })()\n  }, [proxy])\n\n  return null\n}\n```\n\n### createComlinkSingleton\u003cT = unknown\u003e(initWorker: Worker, options: WorkerOptions = {}): () =\u003e { proxy\u003cT\u003e, worker }\n\nIf you want to keep the same state between multiple components, be my guest. Not the best choice for modularity, but hey, I just make the tools. Notice that the worker is never terminated, and must be done on demand (on `worker.terminate()`)\n\n```tsx\nconst useSingleton = createComlinkSingleton\u003c() =\u003e Bad\u003e(new Worker('./bad.idea.worker.js'))\n\nconst MyComponent: React.FC = () =\u003e {\n  const { proxy } = useSingleton()\n\n  useEffect(() =\u003e {\n    (async () =\u003e {\n      const isBad = await proxy()\n    })()\n  }, [proxy])\n\n  return null\n}\n```\n\n## Comlink\n\nMake sure the read the Comlink documentation, being the most important part what can be [structure cloned](https://github.com/GoogleChromeLabs/comlink#comlinktransfervalue-transferables-and-comlinkproxyvalue)\n\n## Caveats\n\nEvery function with Comlink is async (because you're basically communicating to another thread through web workers), even class instantiation (using new), so local state can't be retrieved automatically from the exposed class, object or function, having to resort to wrapping some code with self invoking `async` functions, or relying on `.then()`. If your render depends on the external worker result, you'll have to think of an intermediate state.\n\nAlthough the worker will be terminated when the component is unmounted, your code might try to \"set\" the state of an unmounted component because of how workers work (:P) on their own separate thread in a truly async manner.\n\nIn the future, when `react-cache` and Concurrent Mode is upon us, this library will be updated to work nicely with Suspense and the async nature of Comlink\n\n## Example\n\nRun `npm run example` from root then open `http://localhost:1234`\n\n## TODO\n\nWrite tests (hardcore web workers tests)\n\n## License\n\nMIT","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpocesar%2Freact-use-comlink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpocesar%2Freact-use-comlink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpocesar%2Freact-use-comlink/lists"}