{"id":15311760,"url":"https://github.com/aslemammad/jotai","last_synced_at":"2025-10-08T21:30:31.799Z","repository":{"id":39913291,"uuid":"301622613","full_name":"Aslemammad/jotai","owner":"Aslemammad","description":"👻 Primitive, flexible state management for React","archived":false,"fork":true,"pushed_at":"2024-12-16T07:33:20.000Z","size":13392,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-22T09:32:10.450Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://jotai.surge.sh","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"pmndrs/jotai","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Aslemammad.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null},"funding":{"github":["dai-shi"],"patreon":null,"open_collective":"jotai","ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2020-10-06T05:25:30.000Z","updated_at":"2022-02-08T09:02:03.000Z","dependencies_parsed_at":"2023-01-17T18:45:53.988Z","dependency_job_id":"515af9be-6004-4154-a733-90bdc50a7013","html_url":"https://github.com/Aslemammad/jotai","commit_stats":{"total_commits":415,"total_committers":30,"mean_commits":"13.833333333333334","dds":0.4891566265060241,"last_synced_commit":"9cfe83a3be8a7e633081873088c9c53bd57af3c1"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aslemammad%2Fjotai","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aslemammad%2Fjotai/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aslemammad%2Fjotai/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aslemammad%2Fjotai/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Aslemammad","download_url":"https://codeload.github.com/Aslemammad/jotai/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235761806,"owners_count":19041410,"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":[],"created_at":"2024-10-01T08:34:25.766Z","updated_at":"2025-10-08T21:30:31.217Z","avatar_url":"https://github.com/Aslemammad.png","language":"TypeScript","funding_links":["https://github.com/sponsors/dai-shi","https://opencollective.com/jotai"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/title.svg\" alt=\"jotai\" /\u003e\n\u003c/p\u003e\n\nPrimitive and flexible state management for React\n\n`npm i jotai`\n\n[![Build Status](https://img.shields.io/github/workflow/status/pmndrs/jotai/Lint?style=flat\u0026colorA=000000\u0026colorB=000000)](https://github.com/pmndrs/jotai/actions?query=workflow%3ALint)\n[![Build Size](https://img.shields.io/bundlephobia/min/jotai?label=bundle%20size\u0026style=flat\u0026colorA=000000\u0026colorB=000000)](https://bundlephobia.com/result?p=jotai)\n[![Version](https://img.shields.io/npm/v/jotai?style=flat\u0026colorA=000000\u0026colorB=000000)](https://www.npmjs.com/package/jotai)\n[![Downloads](https://img.shields.io/npm/dt/jotai.svg?style=flat\u0026colorA=000000\u0026colorB=000000)](https://www.npmjs.com/package/jotai)\n[![Discord Shield](https://img.shields.io/discord/740090768164651008?style=flat\u0026colorA=000000\u0026colorB=000000\u0026label=discord\u0026logo=discord\u0026logoColor=ffffff)](https://discord.gg/poimandres)\n[![Open Collective](https://img.shields.io/opencollective/all/jotai?style=flat\u0026colorA=000000\u0026colorB=000000)](https://opencollective.com/jotai)\n\nJotai is pronounced \"joe-tie\" and means \"state\" in Japanese.\n\nYou can try live demos in the following:\n[Demo 1](https://codesandbox.io/s/jotai-demo-47wvh) |\n[Demo 2](https://codesandbox.io/s/jotai-demo-forked-x2g5d).\n\n#### How does Jotai differ from Recoil?\n\n- Minimalistic API\n- No string keys\n- TypeScript oriented\n\n### First create a primitive atom\n\nAn atom represents a piece of state. All you need is to specify an initial\nvalue, which can be primitive values like strings and numbers, objects and\narrays. You can create as many primitive atoms as you want.\n\n```jsx\nimport { atom } from 'jotai'\n\nconst countAtom = atom(0)\nconst countryAtom = atom('Japan')\nconst citiesAtom = atom(['Tokyo', 'Kyoto', 'Osaka'])\nconst mangaAtom = atom({ 'Dragon Ball': 1984, 'One Piece': 1997, Naruto: 1999 })\n```\n\n### Use the atom in your components\n\nIt can be used like `React.useState`:\n\n```jsx\nimport { useAtom } from 'jotai'\n\nfunction Counter() {\n  const [count, setCount] = useAtom(countAtom)\n  return (\n    \u003ch1\u003e\n      {count}\n      \u003cbutton onClick={() =\u003e setCount(c =\u003e c + 1)}\u003eone up\u003c/button\u003e\n```\n\n### Create derived atoms with computed values\n\nA new read-only atom can be created from existing atoms by passing a read\nfunction as the first argument. `get` allows you to fetch the contextual value\nof any atom.\n\n```jsx\nconst doubledCountAtom = atom((get) =\u003e get(countAtom) * 2)\n\nfunction DoubleCounter() {\n  const [doubledCount] = useAtom(doubledCountAtom)\n  return \u003ch2\u003e{doubledCount}\u003c/h2\u003e\n```\n\n## Recipes\n\n### Creating an atom from multiple atoms\n\nYou can combine multiple atoms to create a derived atom.\n\n```jsx\nconst count1 = atom(1)\nconst count2 = atom(2)\nconst count3 = atom(3)\n\nconst sum = atom((get) =\u003e get(count1) + get(count2) + get(count3))\n```\n\nOr if you like fp patterns ...\n\n```jsx\nconst atoms = [count1, count2, count3, ...otherAtoms]\nconst sum = atom((get) =\u003e atoms.map(get).reduce((acc, count) =\u003e acc + count))\n```\n\n### Derived async atoms \u003cimg src=\"https://img.shields.io/badge/-needs_suspense-black\" alt=\"needs suspense\" /\u003e\n\nYou can make the read function an async function too.\n\n```jsx\nconst urlAtom = atom(\"https://json.host.com\")\nconst fetchUrlAtom = atom(\n  async (get) =\u003e {\n    const response = await fetch(get(urlAtom))\n    return await response.json()\n  }\n)\n\nfunction Status() {\n  // Re-renders the component after urlAtom changed and the async function above concludes\n  const [json] = useAtom(fetchUrlAtom)\n```\n\n### You can create a writable derived atom\n\nSpecify a write function at the second argument. `get` will return the current\nvalue of an atom. `set` will update an atoms value.\n\n```jsx\nconst decrementCountAtom = atom(\n  (get) =\u003e get(countAtom),\n  (get, set, _arg) =\u003e set(countAtom, get(countAtom) - 1),\n)\n\nfunction Counter() {\n  const [count, decrement] = useAtom(decrementCountAtom)\n  return (\n    \u003ch1\u003e\n      {count}\n      \u003cbutton onClick={decrement}\u003eDecrease\u003c/button\u003e\n```\n\n### Write only atoms\n\nJust do not define a read function.\n\n```jsx\nconst multiplyCountAtom = atom(null, (get, set, by) =\u003e set(countAtom, get(countAtom) * by))\n\nfunction Controls() {\n  const [, multiply] = useAtom(multiplyCountAtom)\n  return \u003cbutton onClick={() =\u003e multiply(3)}\u003etriple\u003c/button\u003e\n```\n\n### Async actions \u003cimg src=\"https://img.shields.io/badge/-needs_suspense-black\" alt=\"needs suspense\" /\u003e\n\nJust make the write function an async function and call `set` when you're ready.\n\n```jsx\nconst fetchCountAtom = atom(\n  (get) =\u003e get(countAtom),\n  async (_get, set, url) =\u003e {\n    const response = await fetch(url)\n    set(countAtom, (await response.json()).count)\n  }\n)\n\nfunction Controls() {\n  const [count, compute] = useAtom(fetchCountAtom)\n  return \u003cbutton onClick={() =\u003e compute(\"http://count.host.com\")}\u003ecompute\u003c/button\u003e\n```\n\n## Installation notes\n\nThis package requires some peer dependencies, which you need to install by\nyourself.\n\n```bash\nyarn add jotai react\n```\n\n## More documents\n\n- Introduction\n  - [Comparison](./docs/introduction/comparison.md)\n  - [Basics](./docs/introduction/basics.md)\n  - [Async](./docs/introduction/async.md)\n  - [Showcase](./docs/introduction/showcase.md)\n- Guides\n  - [TypeScript](./docs/guides/typescript.md)\n  - [Debugging](./docs/guides/debugging.md)\n  - [Persistence](./docs/guides/persistence.md)\n  - [Next.js](./docs/guides/nextjs.md)\n  - [Resettable](./docs/guides/resettable.md)\n- API\n  - [Core](./docs/api/core.md)\n  - [Utils](./docs/api/utils.md)\n  - [Devtools](./docs/api/devtools.md)\n  - [Immer](./docs/api/immer.md)\n  - [Optics](./docs/api/optics.md)\n  - [Query](./docs/api/query.md)\n  - [XState](./docs/api/xstate.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faslemammad%2Fjotai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faslemammad%2Fjotai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faslemammad%2Fjotai/lists"}