{"id":13459621,"url":"https://github.com/pmndrs/jotai","last_synced_at":"2025-12-26T05:31:14.395Z","repository":{"id":37019599,"uuid":"286867459","full_name":"pmndrs/jotai","owner":"pmndrs","description":"👻 Primitive and flexible state management for React","archived":false,"fork":false,"pushed_at":"2025-05-10T13:45:40.000Z","size":14305,"stargazers_count":19923,"open_issues_count":2,"forks_count":661,"subscribers_count":66,"default_branch":"main","last_synced_at":"2025-05-12T18:15:17.381Z","etag":null,"topics":["atomic","hacktoberfest","management","react","state"],"latest_commit_sha":null,"homepage":"https://jotai.org","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/pmndrs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":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":["https://daishi.gumroad.com/l/learn-jotai"]}},"created_at":"2020-08-11T23:15:36.000Z","updated_at":"2025-05-12T12:11:36.000Z","dependencies_parsed_at":"2023-10-17T05:34:30.366Z","dependency_job_id":"fc9d3392-96fb-4819-ba59-734291e41e2c","html_url":"https://github.com/pmndrs/jotai","commit_stats":{"total_commits":1481,"total_committers":216,"mean_commits":6.856481481481482,"dds":0.6266036461850102,"last_synced_commit":"62c489273eccc3799a2fceaf6d068d2d8447a718"},"previous_names":[],"tags_count":188,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmndrs%2Fjotai","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmndrs%2Fjotai/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmndrs%2Fjotai/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmndrs%2Fjotai/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pmndrs","download_url":"https://codeload.github.com/pmndrs/jotai/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253795161,"owners_count":21965487,"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":["atomic","hacktoberfest","management","react","state"],"created_at":"2024-07-31T10:00:23.181Z","updated_at":"2025-12-15T10:45:58.265Z","avatar_url":"https://github.com/pmndrs.png","language":"TypeScript","funding_links":["https://github.com/sponsors/dai-shi","https://opencollective.com/jotai","https://daishi.gumroad.com/l/learn-jotai"],"categories":["四、状态管理与数据获取","TypeScript","Utilities","Frontend React","Tools","State Management","Explanation of each State Management","数据流","React 相关","语言资源库","前端开发框架及项目","State management:","Packages","Uncategorized","react","📖 Categories","Tools :flashlight:","State management","List","⚛️ React","🌐 Web Development - Frontend"],"sub_categories":["1. 状态管理（同步状态）","State Management","Client-State management","Visual Editor","Jotai","macros","typescript","其他_文本生成、文本对话","Uncategorized","State management","Graphics \u0026 Drawing"],"readme":"\u003cbr\u003e\n\n![Jotai (light mode)](./img/jotai-header-light.png#gh-light-mode-only)\n![Jotai (dark mode)](./img/jotai-header-dark.png#gh-dark-mode-only)\n\n\u003cbr\u003e\n\nvisit [jotai.org](https://jotai.org) or `npm i jotai`\n\n[![Build Status](https://img.shields.io/github/actions/workflow/status/pmndrs/jotai/test.yml?branch=main\u0026style=flat\u0026colorA=000000\u0026colorB=000000)](https://github.com/pmndrs/jotai/actions?query=workflow%3ALint)\n[![Build Size](https://img.shields.io/bundlephobia/minzip/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 scales from a simple useState replacement to an enterprise TypeScript application.\n\n- Minimal core API (2kb)\n- Many utilities and extensions\n- No string keys (compared to Recoil)\n\nExamples: [Demo 1](https://codesandbox.io/s/jotai-demo-47wvh) |\n[Demo 2](https://codesandbox.io/s/jotai-demo-forked-x2g5d)\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\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\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](https://react.dev/reference/react/Suspense)\n\nYou can make the read function an async function too.\n\n```jsx\nconst urlAtom = atom('https://json.host.com')\nconst fetchUrlAtom = atom(async (get) =\u003e {\n  const response = await fetch(get(urlAtom))\n  return await response.json()\n})\n\nfunction Status() {\n  // Re-renders the component after urlAtom is changed and the async function above concludes\n  const [json] = useAtom(fetchUrlAtom)\n  ...\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 the value of an atom.\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\n### Write only derived atoms\n\nJust do not define a read function.\n\n```jsx\nconst multiplyCountAtom = atom(null, (get, set, by) =\u003e\n  set(countAtom, get(countAtom) * by),\n)\n\nfunction Controls() {\n  const [, multiply] = useAtom(multiplyCountAtom)\n  return \u003cbutton onClick={() =\u003e multiply(3)}\u003etriple\u003c/button\u003e\n}\n```\n\n### Async actions\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 (\n    \u003cbutton onClick={() =\u003e compute('http://count.host.com')}\u003ecompute\u003c/button\u003e\n    ...\n```\n\n### Note about functional programming\n\nJotai's fluid interface is no accident — atoms are monads, just like promises!\nMonads are an [established](\u003chttps://en.wikipedia.org/wiki/Monad_(functional_programming)\u003e)\npattern for modular, pure, robust and understandable code which is [optimized for change](https://overreacted.io/optimized-for-change/).\nRead more about [Jotai and monads.](https://jotai.org/docs/basics/functional-programming-and-jotai)\n\n## Links\n\n- [website](https://jotai.org)\n- [documentation](https://jotai.org/docs)\n- [course](https://egghead.io/courses/manage-application-state-with-jotai-atoms-2c3a29f0)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmndrs%2Fjotai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpmndrs%2Fjotai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmndrs%2Fjotai/lists"}