{"id":21868741,"url":"https://github.com/merisbahti/klyva","last_synced_at":"2025-08-16T12:13:32.522Z","repository":{"id":42066337,"uuid":"294615747","full_name":"merisbahti/klyva","owner":"merisbahti","description":"A state management library that follows the React component model","archived":false,"fork":false,"pushed_at":"2024-02-29T11:30:46.000Z","size":798,"stargazers_count":55,"open_issues_count":15,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-03T17:07:36.395Z","etag":null,"topics":["atom","atoms","hook","optics","react","react-components"],"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/merisbahti.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-09-11T06:43:10.000Z","updated_at":"2024-04-14T17:52:09.000Z","dependencies_parsed_at":"2025-04-16T04:01:09.176Z","dependency_job_id":null,"html_url":"https://github.com/merisbahti/klyva","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/merisbahti/klyva","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/merisbahti%2Fklyva","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/merisbahti%2Fklyva/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/merisbahti%2Fklyva/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/merisbahti%2Fklyva/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/merisbahti","download_url":"https://codeload.github.com/merisbahti/klyva/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/merisbahti%2Fklyva/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270709037,"owners_count":24631992,"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","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["atom","atoms","hook","optics","react","react-components"],"created_at":"2024-11-28T05:15:11.828Z","updated_at":"2025-08-16T12:13:32.499Z","avatar_url":"https://github.com/merisbahti.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🪓 klyva\n\nScalable state management for React.\n\nMinimal API, with reactive, composable and decomposable state!\n\n[📺 10 minute tutorial](https://www.youtube.com/watch?v=xIyI9pYQLcs)\n\n# How to\n\n## Create an atom\n\nA base atom can be constructed by giving the `atom` a value.\n\n```typescript\nconst countAtom = atom(5)\n```\n\n## useAtom\n\nThe `useAtom` hook subscribes to changes to the atom, so if it's updated, then this component is notified and updated.\nThe hook is similar to react's `useState` in that it gives a `setState` function.\n\n```tsx\nconst MyComponent = () =\u003e {\n  const [value, setValue] = useAtom(countAtom)\n  const increase = () =\u003e setValue(oldValue =\u003e oldValue + 1)\n  return \u003cbutton onClick={increase}\u003e{value}\u003c/button\u003e\n}\n```\n\n## Composition\n\nAtoms are composable. Meaning that you can *glue* together two atoms using the `get` function, when any dependant atoms are updated, the derived atom is updated:\n\n```typescript\nconst atomOne = atom(10)\nconst atomTwo = atom(20)\nconst sumAtom = atom(get =\u003e get(atomOne) + get(atomTwo))\n```\n\n## Decomposition\n\nYou can focus on a smaller part of an atom, to view and update that smaller part (`focusedAtom`) - which in turn updates the derivee (`objectAtom`).\n\n```typescript\nconst objectAtom = atom({a: 10})\nconst focusedAtom = focusAtom(objectAtom, optic =\u003e optic.prop('a'))\n\nconst MyComponent = () =\u003e {\n  const [value, setValue] = useAtom(focusedAtom)\n  const increase = () =\u003e setValue(oldValue =\u003e oldValue + 1)\n  return \u003cbutton onClick={increase}\u003e{value}\u003c/button\u003e\n}\n```\n\nSee more about optics at:\nhttps://github.com/akheron/optics-ts\n\n## Usage outside of react\n\n### Get value \nUse the `getValue` function to get the atoms current value:\n\n```tsx\nconst counterAtom = atom(0)\ncounterAtom.getValue() // 0\n```\n\n### Update it\nAtoms have an `update` function, which can be used to update it outside of react:\n\n```typescript\nconst numberAtom = atom(5)\n\nnumberAtom.update(6)\nnumberAtom.update(value =\u003e value + 1)\n```\n\n### Subscribe \nUse the `subscribe` function to subscribe to changes for this atom:\n\n```tsx\nconst counterAtom = atom(0)\ncounterAtom.subscribe(count =\u003e console.log(`The count is: ${count}`))\ncounterAtom.update(count =\u003e count + 1)\n// console: The count is: 1\n```\n\n\n## Advanced example\n\nWhen you have an atom which contains a list, and you want to delegate control of each list item, you can use the `useAtomSlice`-hook like this:\n\n```tsx\nconst listAtom = atom([0,0,0])\n\nconst CounterList = () =\u003e {\n  const counterAtoms = useAtomSlice(listAtom)\n  const addCounter = () =\u003e listAtom.update(counters =\u003e [...counters, 0])\n  return (\n    \u003c\u003e\n      \u003cul\u003e\n        {counterAtoms.map((atom) =\u003e \u003cCounter counterAtom={atom} onRemove={atom.remove} /\u003e)}\n      \u003c/ul\u003e\n      \u003cbutton onClick={addCounter}\u003e\n        Add counter\n      \u003c/button\u003e\n    \u003c/\u003e\n  )\n}\n\nconst Counter = ({counterAtom, onRemove}: {counterAtom: Atom\u003cnumber\u003e, onRemove: () =\u003e void}) =\u003e {\n  const [count, setCount] = useAtom(counterAtom)\n  return (\n    \u003cli\u003e\n      \u003cbutton onClick={() =\u003e setCount(v =\u003e v + 1)}\u003e{count}\u003c/button\u003e\n      \u003cbutton onClick={onRemove}\u003eRemove me\u003c/button\u003e\n    \u003c/li\u003e\n  )\n}\n```\n\nCurious? See [codesandbox](https://codesandbox.io/s/adoring-waterfall-2ot5y?file=/src/App.tsx)!\n\n## Differences from jotai and recoil\n\n* No `\u003cProvider\u003e` needed\n* No `key` needed for atom\n* More performant: Atoms are _minimally_ expensive to create, and you can create them almost for free in react components.\n* Usage outside of react components is supported, so you can listen to changes and update atoms from outside of a react context.\n\n## Install\n\n### Using npm\n```bash\nnpm i klyva\n```\n\n### Using yarn\n```bash\nyarn add klyva\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmerisbahti%2Fklyva","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmerisbahti%2Fklyva","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmerisbahti%2Fklyva/lists"}