Full Code of pmndrs/jotai for AI

main c3db721a53d8 cached
326 files
960.9 KB
277.2k tokens
258 symbols
1 requests
Download .txt
Showing preview only (1,039K chars total). Download the full file or copy to clipboard to get everything.
Repository: pmndrs/jotai
Branch: main
Commit: c3db721a53d8
Files: 326
Total size: 960.9 KB

Directory structure:
gitextract_mot3st09/

├── .codesandbox/
│   └── ci.json
├── .github/
│   ├── DISCUSSION_TEMPLATE/
│   │   └── bug-report.yml
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── config.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── compressed-size.yml
│       ├── ecosystem-ci.yml
│       ├── livecodes-post-comment.yml
│       ├── livecodes-preview.yml
│       ├── preview-release.yml
│       ├── publish.yml
│       ├── stale-discussions.yml
│       ├── test-multiple-builds.yml
│       ├── test-multiple-versions.yml
│       ├── test-old-typescript.yml
│       └── test.yml
├── .gitignore
├── .livecodes/
│   └── react.json
├── .prettierignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── babel.config.mjs
├── benchmarks/
│   ├── .gitignore
│   ├── simple-read.ts
│   ├── simple-write.ts
│   └── subscribe-write.ts
├── docs/
│   ├── basics/
│   │   ├── comparison.mdx
│   │   ├── concepts.mdx
│   │   ├── functional-programming-and-jotai.mdx
│   │   └── showcase.mdx
│   ├── core/
│   │   ├── atom.mdx
│   │   ├── provider.mdx
│   │   ├── store.mdx
│   │   └── use-atom.mdx
│   ├── extensions/
│   │   ├── cache.mdx
│   │   ├── effect.mdx
│   │   ├── immer.mdx
│   │   ├── location.mdx
│   │   ├── optics.mdx
│   │   ├── query.mdx
│   │   ├── redux.mdx
│   │   ├── relay.mdx
│   │   ├── scope.mdx
│   │   ├── trpc.mdx
│   │   ├── urql.mdx
│   │   ├── valtio.mdx
│   │   ├── xstate.mdx
│   │   └── zustand.mdx
│   ├── guides/
│   │   ├── async.mdx
│   │   ├── atoms-in-atom.mdx
│   │   ├── composing-atoms.mdx
│   │   ├── core-internals.mdx
│   │   ├── debugging.mdx
│   │   ├── initialize-atom-on-render.mdx
│   │   ├── migrating-to-v2-api.mdx
│   │   ├── nextjs.mdx
│   │   ├── performance.mdx
│   │   ├── persistence.mdx
│   │   ├── react-native.mdx
│   │   ├── remix.mdx
│   │   ├── resettable.mdx
│   │   ├── testing.mdx
│   │   ├── typescript.mdx
│   │   ├── using-store-outside-react.mdx
│   │   ├── vite.mdx
│   │   └── waku.mdx
│   ├── index.mdx
│   ├── recipes/
│   │   ├── atom-with-broadcast.mdx
│   │   ├── atom-with-compare.mdx
│   │   ├── atom-with-debounce.mdx
│   │   ├── atom-with-listeners.mdx
│   │   ├── atom-with-refresh-and-default.mdx
│   │   ├── atom-with-refresh.mdx
│   │   ├── atom-with-toggle-and-storage.mdx
│   │   ├── atom-with-toggle.mdx
│   │   ├── custom-useatom-hooks.mdx
│   │   ├── large-objects.mdx
│   │   ├── use-atom-effect.mdx
│   │   └── use-reducer-atom.mdx
│   ├── third-party/
│   │   ├── bunja.mdx
│   │   ├── derive.mdx
│   │   └── history.mdx
│   ├── tools/
│   │   ├── babel.mdx
│   │   ├── devtools.mdx
│   │   └── swc.mdx
│   └── utilities/
│       ├── async.mdx
│       ├── callback.mdx
│       ├── family.mdx
│       ├── lazy.mdx
│       ├── reducer.mdx
│       ├── resettable.mdx
│       ├── select.mdx
│       ├── split.mdx
│       ├── ssr.mdx
│       └── storage.mdx
├── eslint.config.mjs
├── examples/
│   ├── hacker_news/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── index.tsx
│   │   │   ├── styles.css
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── hello/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── index.tsx
│   │   │   ├── prism.css
│   │   │   ├── style.css
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── mega-form/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── index.tsx
│   │   │   ├── initialValue.ts
│   │   │   ├── style.css
│   │   │   ├── useAtomSlice.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── starter/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── index.css
│   │   │   ├── index.tsx
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── text_length/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── index.tsx
│   │   │   └── react-app-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── todos/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── index.tsx
│   │   │   ├── styles.css
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   └── todos_with_atomFamily/
│       ├── README.md
│       ├── index.html
│       ├── package.json
│       ├── public/
│       │   └── index.html
│       ├── src/
│       │   ├── App.tsx
│       │   ├── index.tsx
│       │   ├── styles.css
│       │   └── vite-env.d.ts
│       ├── tsconfig.json
│       └── vite.config.ts
├── package.json
├── pnpm-workspace.yaml
├── rollup.config.mjs
├── src/
│   ├── babel/
│   │   ├── plugin-debug-label.ts
│   │   ├── plugin-react-refresh.ts
│   │   ├── preset.ts
│   │   └── utils.ts
│   ├── index.ts
│   ├── react/
│   │   ├── Provider.ts
│   │   ├── useAtom.ts
│   │   ├── useAtomValue.ts
│   │   ├── useSetAtom.ts
│   │   ├── utils/
│   │   │   ├── useAtomCallback.ts
│   │   │   ├── useHydrateAtoms.ts
│   │   │   ├── useReducerAtom.ts
│   │   │   └── useResetAtom.ts
│   │   └── utils.ts
│   ├── react.ts
│   ├── types.d.ts
│   ├── utils.ts
│   ├── vanilla/
│   │   ├── atom.ts
│   │   ├── internals.ts
│   │   ├── store.ts
│   │   ├── typeUtils.ts
│   │   ├── utils/
│   │   │   ├── atomFamily.ts
│   │   │   ├── atomWithDefault.ts
│   │   │   ├── atomWithLazy.ts
│   │   │   ├── atomWithObservable.ts
│   │   │   ├── atomWithReducer.ts
│   │   │   ├── atomWithRefresh.ts
│   │   │   ├── atomWithReset.ts
│   │   │   ├── atomWithStorage.ts
│   │   │   ├── constants.ts
│   │   │   ├── freezeAtom.ts
│   │   │   ├── loadable.ts
│   │   │   ├── selectAtom.ts
│   │   │   ├── splitAtom.ts
│   │   │   └── unwrap.ts
│   │   └── utils.ts
│   └── vanilla.ts
├── tests/
│   ├── babel/
│   │   ├── plugin-debug-label.test.ts
│   │   ├── plugin-react-refresh.test.ts
│   │   └── preset.test.ts
│   ├── react/
│   │   ├── abortable.test.tsx
│   │   ├── async.test.tsx
│   │   ├── async2.test.tsx
│   │   ├── basic.test.tsx
│   │   ├── dependency.test.tsx
│   │   ├── error.test.tsx
│   │   ├── items.test.tsx
│   │   ├── onmount.test.tsx
│   │   ├── optimization.test.tsx
│   │   ├── provider.test.tsx
│   │   ├── transition.test.tsx
│   │   ├── types.test.tsx
│   │   ├── useAtomValue.test.tsx
│   │   ├── useSetAtom.test.tsx
│   │   ├── utils/
│   │   │   ├── types.test.tsx
│   │   │   ├── useAtomCallback.test.tsx
│   │   │   ├── useHydrateAtoms.test.tsx
│   │   │   ├── useReducerAtom.test.tsx
│   │   │   └── useResetAtom.test.tsx
│   │   └── vanilla-utils/
│   │       ├── atomFamily.test.tsx
│   │       ├── atomWithDefault.test.tsx
│   │       ├── atomWithObservable.test.tsx
│   │       ├── atomWithReducer.test.tsx
│   │       ├── atomWithRefresh.test.tsx
│   │       ├── atomWithStorage.test.tsx
│   │       ├── freezeAtom.test.tsx
│   │       ├── loadable.test.tsx
│   │       ├── selectAtom.test.tsx
│   │       └── splitAtom.test.tsx
│   ├── setup.ts
│   ├── test-utils.ts
│   └── vanilla/
│       ├── basic.test.tsx
│       ├── dependency.test.tsx
│       ├── derive.test.tsx
│       ├── effect.test.ts
│       ├── internals.test.tsx
│       ├── memoryleaks.test.ts
│       ├── store.test.tsx
│       ├── storedev.test.tsx
│       ├── types.test.tsx
│       └── utils/
│           ├── atomFamily.test.ts
│           ├── atomWithDefault.test.ts
│           ├── atomWithLazy.test.ts
│           ├── atomWithRefresh.test.ts
│           ├── atomWithReset.test.ts
│           ├── loadable.test.ts
│           ├── types.test.tsx
│           └── unwrap.test.ts
├── tsconfig.json
├── vitest.config.mts
└── website/
    ├── .babelrc
    ├── .gitignore
    ├── README.md
    ├── api/
    │   └── contact.js
    ├── gatsby-browser.js
    ├── gatsby-config.js
    ├── gatsby-node.js
    ├── gatsby-shared.js
    ├── gatsby-ssr.js
    ├── jsconfig.json
    ├── package.json
    ├── postcss.config.js
    ├── reach-router.js
    ├── src/
    │   ├── api/
    │   │   └── contact.js
    │   ├── atoms/
    │   │   └── index.js
    │   ├── components/
    │   │   ├── button.js
    │   │   ├── client-only.js
    │   │   ├── code-sandbox.js
    │   │   ├── code.js
    │   │   ├── core-demo.js
    │   │   ├── credits.js
    │   │   ├── docs.js
    │   │   ├── extensions-demo.js
    │   │   ├── external-link.js
    │   │   ├── footer.js
    │   │   ├── headline.js
    │   │   ├── icon.js
    │   │   ├── inline-code.js
    │   │   ├── intro.js
    │   │   ├── jotai.js
    │   │   ├── layout.js
    │   │   ├── logo-cloud.js
    │   │   ├── logo.js
    │   │   ├── main.js
    │   │   ├── mdx.js
    │   │   ├── menu.js
    │   │   ├── meta.js
    │   │   ├── modal.js
    │   │   ├── search-button.js
    │   │   ├── search-modal.js
    │   │   ├── shelf.js
    │   │   ├── sidebar.js
    │   │   ├── stackblitz.js
    │   │   ├── support-modal.js
    │   │   ├── support.js
    │   │   ├── tabs.js
    │   │   ├── toc.js
    │   │   ├── toggle.js
    │   │   ├── utilities-demo.js
    │   │   └── wrapper.js
    │   ├── hooks/
    │   │   └── index.js
    │   ├── pages/
    │   │   ├── 404.js
    │   │   ├── docs/
    │   │   │   └── {Mdx.slug}.js
    │   │   └── index.js
    │   ├── styles/
    │   │   ├── base.css
    │   │   ├── components.css
    │   │   ├── fonts.css
    │   │   ├── index.css
    │   │   ├── layout.css
    │   │   ├── pmndrs.css
    │   │   └── utilities.css
    │   └── utils/
    │       └── index.js
    ├── static/
    │   └── robots.txt
    ├── tailwind.config.js
    └── vercel.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .codesandbox/ci.json
================================================
{
  "packages": ["dist"],
  "sandboxes": [
    "new",
    "react-typescript-react-ts",
    "simple-react-browserify-x9yni",
    "simple-snowpack-react-o1gmx",
    "next-js-uo1h0",
    "next-js-with-custom-babel-config-komw9",
    "react-with-custom-babel-config-z1ebx"
  ],
  "node": "18"
}


================================================
FILE: .github/DISCUSSION_TEMPLATE/bug-report.yml
================================================
labels: ['bug']
body:
  - type: markdown
    attributes:
      value: If you don't have a reproduction link, please choose a different category.
  - type: textarea
    attributes:
      label: Bug Description
      description: Describe the bug you encountered
    validations:
      required: true
  - type: input
    attributes:
      label: Reproduction Link
      description: A link to a [TypeScript Playground](https://www.typescriptlang.org/play), a [StackBlitz Project](https://stackblitz.com/) or something else with a minimal reproduction.
    validations:
      required: true


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [dai-shi] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: jotai # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['https://daishi.gumroad.com/l/learn-jotai'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Assigned issue
about: This is to create a new issue that already has an assignee. Please open a new discussion otherwise.
title: ''
labels: ''
assignees: ''
---


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
  - name: Bug Reports
    url: https://github.com/pmndrs/jotai/discussions/new?category=bug-report
    about: Please post bug reports here.
  - name: Questions
    url: https://github.com/pmndrs/jotai/discussions/new?category=q-a
    about: Please post questions here.
  - name: Other Discussions
    url: https://github.com/pmndrs/jotai/discussions/new/choose
    about: Please post ideas and general discussions here.


================================================
FILE: .github/pull_request_template.md
================================================
## Related Bug Reports or Discussions

Fixes #

## Summary

## Check List

- [ ] `pnpm run fix` for formatting and linting code and docs


================================================
FILE: .github/workflows/compressed-size.yml
================================================
name: Compressed Size

on: [pull_request]

jobs:
  compressed_size:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
      - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: 'lts/*'
          cache: 'pnpm'
      - uses: preactjs/compressed-size-action@49c7ff02f46adc39a83c24e91f6110ba8138a19d # v3
        with:
          pattern: './dist/**/*.{js,mjs}'


================================================
FILE: .github/workflows/ecosystem-ci.yml
================================================
name: Ecosystem CI

on:
  issue_comment:
    types: [created]

jobs:
  trigger:
    runs-on: ubuntu-latest
    if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run') }}
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: 'jotaijs/jotai-ecosystem-ci'
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
      - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: 22
          cache: 'pnpm'
      - run: pnpm install
      - name: Get Short SHA
        id: short_sha
        run: |
          api="https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.issue.number }}"
          sha=$(curl -s -H "Authorization: token $GITHUB_TOKEN" $api | jq -r '.head.sha' | cut -c1-8)
          echo "x=$sha" >> $GITHUB_OUTPUT
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Run Ecosystem CI
        id: run_command
        run: |
          echo "x<<EOF" >> $GITHUB_OUTPUT
          pnpm run ecosystem-ci | tee >(grep -A999 -- '---- Jotai Ecosystem CI Results ----' >> $GITHUB_OUTPUT)
          echo "EOF" >> $GITHUB_OUTPUT
        env:
          JOTAI_PKG: https://pkg.csb.dev/pmndrs/jotai/commit/${{ steps.short_sha.outputs.x }}/jotai
          VERBOSE: 1
      - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
        with:
          issue-number: ${{ github.event.issue.number }}
          body: |
            ## Ecosystem CI Output
            ```
            ${{ steps.run_command.outputs.x }}
            ```
            ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}


================================================
FILE: .github/workflows/livecodes-post-comment.yml
================================================
name: LiveCodes Post Comment

on:
  workflow_run:
    workflows: [LiveCodes Preview]
    types:
      - completed

jobs:
  upload:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    if: >
      github.event.workflow_run.event == 'pull_request' &&
      github.event.workflow_run.conclusion == 'success'
    steps:
      - uses: live-codes/pr-comment-from-artifact@15cb31a249e2336571f5d8cc244f6132b7d90ead # v1.0.1
        with:
          GITHUB_TOKEN: ${{ github.token }}


================================================
FILE: .github/workflows/livecodes-preview.yml
================================================
name: LiveCodes Preview

on: [pull_request]

jobs:
  build_and_prepare:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
      - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: 'lts/*'
          cache: 'pnpm'
      - uses: live-codes/preview-in-livecodes@636df52bd6a29316a7ad7501e7016ffdc6f83468 # v1.2.2
        with:
          install-command: pnpm install
          build-command: pnpm run build
          base-url: 'https://{{LC::REF}}.preview-in-livecodes-demo.pages.dev'


================================================
FILE: .github/workflows/preview-release.yml
================================================
name: Preview Release

on: [push, pull_request]

jobs:
  preview_release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
      - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: 'lts/*'
          cache: 'pnpm'
      - run: pnpm install
      - run: pnpm run build
      - run: pnpm dlx pkg-pr-new publish './dist' --compact --template './examples/*'


================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish

on:
  release:
    types: [published]

permissions:
  id-token: write
  contents: read

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
      - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: 'lts/*'
          registry-url: 'https://registry.npmjs.org'
          cache: 'pnpm'
      - run: pnpm install
      - run: pnpm run build
      - run: npm publish
        working-directory: dist


================================================
FILE: .github/workflows/stale-discussions.yml
================================================
name: Close Stale Discussions

on:
  schedule:
    - cron: '0 0 * * *' # Runs every day at midnight UTC
  workflow_dispatch:

jobs:
  close-stale-discussions:
    runs-on: ubuntu-latest
    permissions:
      discussions: write
    steps:
      - uses: steffen-karlsson/stalesweeper@cbed739a89b490f703d8466fb59b37ddc0915889 # v1.1.1
        with:
          message: 'This discussion has been closed due to inactivity.'
          days-before-close: 180
          close-unanswered: true
          verbose: true


================================================
FILE: .github/workflows/test-multiple-builds.yml
================================================
name: Test Multiple Builds

on:
  push:
    branches: [main]
  pull_request:
    types: [opened, synchronize]

jobs:
  test_multiple_builds:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        build: [cjs, esm, umd]
        env: [development, production]
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
      - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: 'lts/*'
          cache: 'pnpm'
      - run: pnpm install
      - run: pnpm run build
      - name: Use React 17 for production test
        if: ${{ matrix.env == 'production' }}
        run: |
          pnpm add -D react@17.0.2 react-dom@17.0.2 @testing-library/react@12.1.4
      - name: Patch for DEV-ONLY
        if: ${{ matrix.env == 'development' }}
        run: |
          sed -i~ "s/\(it\|describe\)[.a-zA-Z]*('\[DEV-ONLY\]/\1('/" tests/*/*.ts* tests/*/*/*.ts*
          sed -i~ "s/\(it\|describe\)[.a-zA-Z]*('\[PRD-ONLY\]/\1.skip('/" tests/*/*.ts* tests/*/*/*.ts*
      - name: Patch for PRD-ONLY
        if: ${{ matrix.env == 'production' }}
        run: |
          sed -i~ "s/\(it\|describe\)[.a-zA-Z]*('\PRD-ONLY\]/\1('/" tests/*/*.ts* tests/*/*/*.ts*
          sed -i~ "s/\(it\|describe\)[.a-zA-Z]*('\[DEV-ONLY\]/\1.skip('/" tests/*/*.ts* tests/*/*/*.ts*
      - name: Patch for CJS
        if: ${{ matrix.build == 'cjs' }}
        run: |
          sed -i~ "s/resolve('\.\/src\(.*\)\.ts')/resolve('\.\/dist\1.js')/" vitest.config.mts
          sed -i~ "s/import { useResetAtom } from 'jotai\/react\/utils'/const { useResetAtom } = require('..\/..\/..\/dist\/react\/utils.js')/" tests/react/utils/useResetAtom.test.tsx
          sed -i~ "s/import { RESET, atomWithReducer, atomWithReset } from 'jotai\/vanilla\/utils'/const { RESET, atomWithReducer, atomWithReset } = require('..\/..\/..\/dist\/vanilla\/utils.js')/" tests/react/utils/useResetAtom.test.tsx
          perl -i~ -0777 -pe "s/import {[^}]+} from 'jotai\/vanilla\/internals'/const { INTERNAL_buildStoreRev2: INTERNAL_buildStore, INTERNAL_initializeStoreHooksRev2: INTERNAL_initializeStoreHooks, INTERNAL_getBuildingBlocksRev2: INTERNAL_getBuildingBlocks } = require('..\/..\/dist\/vanilla\/internals.js')/g" tests/vanilla/store.test.tsx tests/vanilla/internals.test.tsx tests/vanilla/derive.test.tsx tests/vanilla/effect.test.ts
      - name: Patch for ESM
        if: ${{ matrix.build == 'esm' }}
        run: |
          sed -i~ "s/resolve('\.\/src\(.*\)\.ts')/resolve('\.\/dist\/esm\1.mjs')/" vitest.config.mts
          sed -i~ "1s/^/import.meta.env.MODE='${NODE_ENV}';/" tests/*/*.tsx tests/*/*/*.tsx
        env:
          NODE_ENV: ${{ matrix.env }}
      - name: Patch for UMD
        if: ${{ matrix.build == 'umd' }}
        run: |
          sed -i~ "s/resolve('\.\/src\(.*\)\.ts')/resolve('\.\/dist\/umd\1.${NODE_ENV}.js')/" vitest.config.mts
          rm tests/react/utils/useResetAtom.test.tsx # FIXME we skip this for now. Actually I'm not sure if we really run tests with UMD build
          rm tests/vanilla/store.test.tsx tests/vanilla/internals.test.tsx tests/vanilla/derive.test.tsx tests/vanilla/effect.test.ts # FIXME we skip this for now. Actually I'm not sure if we really run tests with UMD build
        env:
          NODE_ENV: ${{ matrix.env }}
      - name: Patch for SystemJS
        if: ${{ matrix.build == 'system' }}
        run: |
          sed -i~ "s/resolve('\.\/src\(.*\)\.ts')/resolve('\.\/dist\/system\1.${NODE_ENV}.js')/" vitest.config.mts
        env:
          NODE_ENV: ${{ matrix.env }}
      - name: Test ${{ matrix.build }} ${{ matrix.env }}
        run: |
          pnpm run test:spec
        env:
          NODE_ENV: ${{ matrix.env }}


================================================
FILE: .github/workflows/test-multiple-versions.yml
================================================
name: Test Multiple Versions

on:
  push:
    branches: [main]
  pull_request:
    types: [opened, synchronize]

jobs:
  test_multiple_versions:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        react:
          - 16.14.0
          - 17.0.0
          - 18.0.0
          - 18.1.0
          - 18.2.0
          - 18.3.1
          - 19.0.0
          - 19.1.0
          - 19.2.0
          - 19.3.0-canary-46103596-20260305
          - 0.0.0-experimental-46103596-20260305
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
      - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: 'lts/*'
          cache: 'pnpm'
      - run: pnpm install
      - name: Install legacy testing-library
        if: ${{ startsWith(matrix.react, '16.') || startsWith(matrix.react, '17.') }}
        run: |
          pnpm add -D @testing-library/react@12.1.4
      - name: Patch for React 17
        if: ${{ startsWith(matrix.react, '17.') }}
        run: |
          pnpm add -D vitest@3.2.4
      - name: Patch for React 16
        if: ${{ startsWith(matrix.react, '16.') }}
        run: |
          sed -i~ '1s/^/import React from "react";/' tests/*/*.tsx tests/*/*/*.tsx
          sed -i~ 's/"jsx": "react-jsx"/"jsx": "react"/' tsconfig.json
          sed -i~ 's/import\.meta\.env[?]\.MODE/"DEVELOPMENT".toLowerCase()/' src/*.ts src/*/*.ts src/*/*/*.ts
      - name: Test Build # we need to build for babel tests
        run: pnpm run build
      - name: Test ${{ matrix.react }}
        run: |
          pnpm add -D react@${{ matrix.react }} react-dom@${{ matrix.react }}
          pnpm run test:spec


================================================
FILE: .github/workflows/test-old-typescript.yml
================================================
name: Test Old TypeScript

on:
  push:
    branches: [main]
  pull_request:
    types: [opened, synchronize]

jobs:
  test_old_typescript:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        typescript:
          - 5.9.3
          - 5.8.3
          - 5.7.3
          - 5.6.3
          - 5.5.4
          - 5.4.5
          - 5.3.3
          - 5.2.2
          - 5.1.6
          - 5.0.4
          - 4.9.5
          - 4.8.4
          - 4.7.4
          - 4.6.4
          - 4.5.5
          - 4.4.4
          - 4.3.5
          - 4.2.3
          - 4.1.5
          - 4.0.5
          - 3.9.7
          - 3.8.3
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
      - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: 'lts/*'
          cache: 'pnpm'
      - run: pnpm install
      - run: pnpm run build
      - name: Patch for all TS
        run: |
          sed -i~ 's/"isolatedDeclarations": true,//' tsconfig.json
      - name: Patch for v4/v3 TS
        if: ${{ startsWith(matrix.typescript, '4.') || startsWith(matrix.typescript, '3.') }}
        run: |
          sed -i~ 's/"verbatimModuleSyntax": true,//' tsconfig.json
      - name: Patch for Newer TS
        if: ${{ matrix.typescript == '4.9.5' || matrix.typescript == '4.8.4' }}
        run: |
          sed -i~ 's/"moduleResolution": "bundler",/"moduleResolution": "node",/' tsconfig.json
          sed -i~ 's/"allowImportingTsExtensions": true,//' tsconfig.json
          sed -i~ 's/"jotai": \["\.\/src\/index\.ts"\],/"jotai": [".\/dist\/index.d.ts"],/' tsconfig.json
          sed -i~ 's/"jotai\/\*": \["\.\/src\/\*\.ts"\]/"jotai\/*": [".\/dist\/*.d.ts"]/' tsconfig.json
          sed -i~ 's/"include": .*/"include": ["src\/types.d.ts", "dist\/**\/*", "tests\/**\/*"],/' tsconfig.json
      - name: Patch for specific TS version
        run: |
          ts_ver_esc=${{ matrix.typescript }}
          ts_ver_esc=${ts_ver_esc//./\\.}
          sed -i~ "s/\/\/ @ts-expect-error .*\[SKIP-TS-${ts_ver_esc}\].*//" tests/*/*.tsx tests/*/*/*.tsx
          sed -i~ "s/\/\/ .*\[ONLY-TS-${ts_ver_esc}\].* @ts-ignore/\/\/ @ts-ignore/" tests/*/*.tsx tests/*/*/*.tsx
      - name: Patch for Old TS
        if: ${{ matrix.typescript == '4.7.4' || matrix.typescript == '4.6.4' || matrix.typescript == '4.5.5' || matrix.typescript == '4.4.4' || matrix.typescript == '4.3.5' || matrix.typescript == '4.2.3' || matrix.typescript == '4.1.5' ||  matrix.typescript == '4.0.5' || startsWith(matrix.typescript, '3.') }}
        run: |
          sed -i~ 's/"target":/"skipLibCheck":true,"target":/' tsconfig.json
          sed -i~ 's/"exactOptionalPropertyTypes": true,//' tsconfig.json
          sed -i~ 's/"moduleResolution": "bundler",/"moduleResolution": "node",/' tsconfig.json
          sed -i~ 's/"allowImportingTsExtensions": true,//' tsconfig.json
          sed -i~ 's/"jotai": \["\.\/src\/index\.ts"\],/"jotai": [".\/dist\/ts3.8\/index.d.ts"],/' tsconfig.json
          sed -i~ 's/"jotai\/\*": \["\.\/src\/\*\.ts"\]/"jotai\/*": [".\/dist\/ts3.8\/*.d.ts"]/' tsconfig.json
          sed -i~ 's/"include": .*/"include": ["src\/types.d.ts", "dist\/**\/*", "tests\/**\/*"],/' tsconfig.json
          pnpm add -D @testing-library/user-event@14.4.3 @types/node@22.2.0 @types/babel__traverse@7.18.2
      - name: Patch for Older TS
        if: ${{ matrix.typescript == '4.2.3' || matrix.typescript == '4.1.5' ||  matrix.typescript == '4.0.5' || startsWith(matrix.typescript, '3.') }}
        run: |
          sed -i~ 's/import\.meta\.env/(import.meta.env as any)/' tests/*/*.tsx tests/*/*/*.tsx
          sed -i~ '1s/^/\/\/\/ <reference types="react\/experimental" \/>\nimport React from "react";/' tests/*/*.tsx tests/*/*/*.tsx
          sed -i~ 's/"jsx": "react-jsx",/"jsx": "react",/' tsconfig.json
          sed -i~ 's/"noUncheckedIndexedAccess": true,//' tsconfig.json
          sed -i~ 's/^import type /import /' tests/*/*.tsx tests/*/*/*.tsx
          pnpm json -I -f package.json -e "this.resolutions={};  this.resolutions['@types/prettier']='2.4.2'; this.resolutions['@types/node']='18.11.18'; this.resolutions['@types/react']='18.2.56';"
          pnpm add -D @types/prettier@2.4.2 @types/node@18.11.18 @types/yargs@17.0.13 @types/react@18.2.56
          rm -r tests/react/vanilla-utils/atomWithObservable.*
      - name: Install old TypeScript
        run: pnpm add -D typescript@${{ matrix.typescript }}
      - name: Patch testing setup for Old TS
        if: ${{ matrix.typescript == '4.6.4' || matrix.typescript == '4.5.5' || matrix.typescript == '4.4.4' || matrix.typescript == '4.3.5' || matrix.typescript == '4.2.3' || matrix.typescript == '4.1.5' ||  matrix.typescript == '4.0.5' || startsWith(matrix.typescript, '3.') }}
        run: |
          pnpm add -D vitest@0.33.0 @vitest/coverage-v8@0.33.0 @vitest/ui@0.33.0
          pnpm add -D @testing-library/jest-dom@5 @types/testing-library__jest-dom@5 
          pnpm add -D @types/jest@27.4.1
          sed -i~ 's/"@testing-library\/jest-dom"/"@types\/testing-library__jest-dom"/' tsconfig.json
      - name: Patch testing setup for older TS
        if: ${{ matrix.typescript == '4.0.5' || startsWith(matrix.typescript, '3.') }}
        run: |
          pnpm add -D @testing-library/user-event@12.1.7 @testing-library/react@11.0.4 @types/react-dom@18.3.1
          rm node_modules/vitest/dist/*.d.ts
          echo "declare module 'vitest'" >> ./src/types.d.ts
      - name: Test ${{ matrix.typescript }}
        run: |
          rm -r node_modules/@types/babel__core/node_modules
          sed -i~ 's/">=4.2": {/">=4.1": {/' node_modules/rxjs/package.json
          pnpm run test:types


================================================
FILE: .github/workflows/test.yml
================================================
name: Test

on:
  push:
    branches: [main]
  pull_request:
    types: [opened, synchronize]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
      - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: 'lts/*'
          cache: 'pnpm'
      - run: pnpm install
      - run: pnpm run test:format
      - run: pnpm run test:types
      - run: pnpm run test:lint
      - run: pnpm run test:spec
      - run: pnpm run build # we don't have any other workflows to test build


================================================
FILE: .gitignore
================================================
# dependencies
node_modules
.pnp
.pnp.js

# testing
coverage

# development
.devcontainer
.vscode

# production
dist
build

# dotenv environment variables file
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# misc
.DS_Store
.idea

# examples
examples/**/*/package-lock.json
examples/**/*/yarn.lock
examples/**/*/pnpm-lock.yaml
examples/**/*/bun.lockb


================================================
FILE: .livecodes/react.json
================================================
{
  "title": "React demo",
  "activeEditor": "script",
  "markup": {
    "language": "html",
    "content": "<div id=\"root\"></div>"
  },
  "style": {
    "language": "css",
    "content": ".App {\n  font-family: sans-serif;\n  text-align: center;\n}\n"
  },
  "script": {
    "language": "jsx",
    "content": "import { StrictMode, Suspense } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { atom, useAtom } from 'jotai';\n\nconst countAtom = atom(0);\n\nconst Counter = () => {\n  const [count, setCount] = useAtom(countAtom);\n  const inc = () => setCount((c) => c + 1);\n  return (\n    <>\n      {count} <button onClick={inc}>+1</button>\n    </>\n  );\n};\n\nconst App = () => (\n  <Suspense fallback=\"Loading...\">\n    <div className=\"App\">\n      <h1>Hello Jotai</h1>\n      <h2>Enjoy coding!</h2>\n      <Counter />\n    </div>\n  </Suspense>\n);\n\nconst rootElement = document.getElementById('root');\nconst root = createRoot(rootElement);\n\nroot.render(\n  <StrictMode>\n    <App />\n  </StrictMode>\n);\n"
  },
  "customSettings": {
    "jotai commit sha": "{{LC::SHORT_SHA}}",
    "imports": {
      "jotai": "{{LC::TO_DATA_URL(./dist/esm/index.mjs)}}",
      "jotai/vanilla": "{{LC::TO_DATA_URL(./dist/esm/vanilla.mjs)}}",
      "jotai/utils": "{{LC::TO_DATA_URL(./dist/esm/utils.mjs)}}",
      "jotai/react": "{{LC::TO_DATA_URL(./dist/esm/react.mjs)}}",
      "jotai/vanilla/utils": "{{LC::TO_DATA_URL(./dist/esm/vanilla/utils.mjs)}}",
      "jotai/react/utils": "{{LC::TO_DATA_URL(./dist/esm/react/utils.mjs)}}"
    }
  }
}


================================================
FILE: .prettierignore
================================================
dist
pnpm-lock.yaml


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

## General Guideline

### Reporting Issues

If you have found what you think is a bug, please [start a discussion](https://github.com/pmndrs/jotai/discussions/new?category=bug-report).

For any usage questions, please [start a discussion](https://github.com/pmndrs/jotai/discussions/new?category=q-a).

### Suggesting New Features

If you are here to suggest a feature, first [start a discussion](https://github.com/pmndrs/jotai/discussions/new?category=ideas) if it does not already exist. From there, we will discuss use-cases for the feature and then finally discuss how it could be implemented.

### Committing

We are applying [conventional commit spec](https://www.conventionalcommits.org/en/v1.0.0/) here. In short, that means a commit has to be one of the following types:

Your commit type must be one of the following:

- **feat**: A new feature.
- **fix**: A bug fix.
- **refactor**: A code change that neither fixes a bug nor adds a feature.
- **chore**: Changes to the build process, configuration, dependencies, CI/CD pipelines, or other auxiliary tools and libraries.
- **docs**: Documentation-only changes.
- **test**: Adding missing or correcting existing tests.

If you are unfamiliar with the usage of conventional commits,
the short version is to simply specify the type as a first word,
and follow it with a colon and a space, then start your message
from a lowercase letter, like this:

```
feat: add a 'foo' type support
```

You can also specify the scope of the commit in the parentheses after a type:

```
fix(react): change the 'bar' parameter type
```

### Development

If you would like to contribute by fixing an open issue or developing a new feature you can use this suggested workflow:

#### General

1. Fork this repository.
2. Create a new feature branch based off the `main` branch.
3. Follow the [Core](#Core) and/or the [Documentation](#Documentation) guide below and come back to this once done.
4. Run `pnpm run fix:format` to format the code.
5. Git stage your required changes and commit. (review the commit guidelines below)
6. Submit the PR for review.

##### Core

1. Run `pnpm install` to install dependencies.
2. Create failing tests for your fix or new feature in the [`tests`](./tests/) folder.
3. Implement your changes.
4. Run `pnpm run build` to build the library. _(Pro-tip: `pnpm run build-watch` runs the build in watch mode)_
5. Run the tests by running `pnpm run test` and ensure that they pass.
6. You can use `pnpm link` to sym-link this package and test it locally on your own project. Alternatively, you may use CodeSandbox CI's canary releases to test the changes in your own project. (requires a PR to be created first)
7. Follow step 4 and onwards from the [General](#General) guide above to bring it to the finish line.

### Pull Requests

Please try to keep your pull request focused in scope and avoid including unrelated commits.

After you have submitted your pull request, we'll try to get back to you as soon as possible. We may suggest some changes or request improvements, therefore, please check ✅ ["Allow edits from maintainers"](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) on your PR.

## Jotai-specific Guideline

##### Documentation

1. Navigate to the [`website`](./website/) folder. (e.g., `cd website`)
2. Run `pnpm install` to install dependencies in the `website` folder.
3. Run `pnpm run dev` to start the dev server.
4. Navigate to [`http://localhost:9000`](http://localhost:9000) to view the documents.
5. Navigate to the [`docs`](./docs/) folder and make necessary changes to the documents.
6. Add your changes to the documents and see them live reloaded in the browser.
7. Follow step 4 and onwards from the [General](#General) guide above to bring it to the finish line.

Thank you for contributing! :heart:


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Poimandres

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<br>

![Jotai (light mode)](./img/jotai-header-light.png#gh-light-mode-only)
![Jotai (dark mode)](./img/jotai-header-dark.png#gh-dark-mode-only)

<br>

visit [jotai.org](https://jotai.org) or `npm i jotai`

[![Build Status](https://img.shields.io/github/actions/workflow/status/pmndrs/jotai/test.yml?branch=main&style=flat&colorA=000000&colorB=000000)](https://github.com/pmndrs/jotai/actions/workflows/test.yml?query=branch%3Amain)
[![Build Size](https://img.shields.io/bundlephobia/minzip/jotai?label=bundle%20size&style=flat&colorA=000000&colorB=000000)](https://bundlephobia.com/result?p=jotai)
[![Version](https://img.shields.io/npm/v/jotai?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/jotai)
[![Downloads](https://img.shields.io/npm/dt/jotai.svg?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/jotai)
[![Discord Shield](https://img.shields.io/discord/740090768164651008?style=flat&colorA=000000&colorB=000000&label=discord&logo=discord&logoColor=ffffff)](https://discord.gg/poimandres)
[![Open Collective](https://img.shields.io/opencollective/all/jotai?style=flat&colorA=000000&colorB=000000)](https://opencollective.com/jotai)

Jotai scales from a simple useState replacement to an enterprise TypeScript application.

- Minimal core API (2kb)
- Many utilities and extensions
- No string keys (compared to Recoil)

Examples: [Demo 1](https://codesandbox.io/s/jotai-demo-47wvh) |
[Demo 2](https://codesandbox.io/s/jotai-demo-forked-x2g5d)

### First, create a primitive atom

An atom represents a piece of state. All you need is to specify an initial
value, which can be primitive values like strings and numbers, objects, and
arrays. You can create as many primitive atoms as you want.

```jsx
import { atom } from 'jotai'

const countAtom = atom(0)
const countryAtom = atom('Japan')
const citiesAtom = atom(['Tokyo', 'Kyoto', 'Osaka'])
const mangaAtom = atom({ 'Dragon Ball': 1984, 'One Piece': 1997, Naruto: 1999 })
```

### Use the atom in your components

It can be used like `React.useState`:

```jsx
import { useAtom } from 'jotai'

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  return (
    <h1>
      {count}
      <button onClick={() => setCount((c) => c + 1)}>one up</button>
      ...
```

### Create derived atoms with computed values

A new read-only atom can be created from existing atoms by passing a read
function as the first argument. `get` allows you to fetch the contextual value
of any atom.

```jsx
const doubledCountAtom = atom((get) => get(countAtom) * 2)

function DoubleCounter() {
  const [doubledCount] = useAtom(doubledCountAtom)
  return <h2>{doubledCount}</h2>
}
```

### Creating an atom from multiple atoms

You can combine multiple atoms to create a derived atom.

```jsx
const count1 = atom(1)
const count2 = atom(2)
const count3 = atom(3)

const sum = atom((get) => get(count1) + get(count2) + get(count3))
```

Or if you like fp patterns ...

```jsx
const atoms = [count1, count2, count3, ...otherAtoms]
const sum = atom((get) => atoms.map(get).reduce((acc, count) => acc + count))
```

### Derived async atoms [<img src="https://img.shields.io/badge/-needs_suspense-black" alt="needs suspense" />](https://react.dev/reference/react/Suspense)

You can make the read function an async function too.

```jsx
const urlAtom = atom('https://json.host.com')
const fetchUrlAtom = atom(async (get) => {
  const response = await fetch(get(urlAtom))
  return await response.json()
})

function Status() {
  // Re-renders the component after urlAtom is changed and the async function above concludes
  const [json] = useAtom(fetchUrlAtom)
  ...
```

### You can create a writable derived atom

Specify a write function at the second argument. `get` will return the current
value of an atom. `set` will update the value of an atom.

```jsx
const decrementCountAtom = atom(
  (get) => get(countAtom),
  (get, set, _arg) => set(countAtom, get(countAtom) - 1)
)

function Counter() {
  const [count, decrement] = useAtom(decrementCountAtom)
  return (
    <h1>
      {count}
      <button onClick={decrement}>Decrease</button>
      ...
```

### Write only derived atoms

Just do not define a read function.

```jsx
const multiplyCountAtom = atom(null, (get, set, by) =>
  set(countAtom, get(countAtom) * by),
)

function Controls() {
  const [, multiply] = useAtom(multiplyCountAtom)
  return <button onClick={() => multiply(3)}>triple</button>
}
```

### Async actions

Just make the write function an async function and call `set` when you're ready.

```jsx
const fetchCountAtom = atom(
  (get) => get(countAtom),
  async (_get, set, url) => {
    const response = await fetch(url)
    set(countAtom, (await response.json()).count)
  }
)

function Controls() {
  const [count, compute] = useAtom(fetchCountAtom)
  return (
    <button onClick={() => compute('http://count.host.com')}>compute</button>
    ...
```

### Note about functional programming

Jotai's fluid interface is no accident — atoms are monads, just like promises!
Monads are an [established](<https://en.wikipedia.org/wiki/Monad_(functional_programming)>)
pattern for modular, pure, robust and understandable code which is [optimized for change](https://overreacted.io/optimized-for-change/).
Read more about [Jotai and monads.](https://jotai.org/docs/basics/functional-programming-and-jotai)

## Links

- [website](https://jotai.org)
- [documentation](https://jotai.org/docs)
- [course](https://egghead.io/courses/manage-application-state-with-jotai-atoms-2c3a29f0)


================================================
FILE: babel.config.mjs
================================================
export default (api, targets) => {
  // https://babeljs.io/docs/en/config-files#config-function-api
  const isTestEnv = api.env('test')

  return {
    babelrc: false,
    ignore: ['./node_modules'],
    presets: [
      [
        '@babel/preset-env',
        {
          loose: true,
          modules: isTestEnv ? 'commonjs' : false,
          targets: isTestEnv ? { node: 'current' } : targets,
        },
      ],
    ],
    plugins: [
      [
        '@babel/plugin-transform-react-jsx',
        {
          runtime: 'automatic',
        },
      ],
      ['@babel/plugin-transform-typescript', { isTSX: true }],
    ],
  }
}


================================================
FILE: benchmarks/.gitignore
================================================
/*.json
/*.html


================================================
FILE: benchmarks/simple-read.ts
================================================
#!/usr/bin/env npx tsx

/// <reference types="node" />

import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { add, complete, cycle, save, suite } from 'benny'
import { atom } from '../src/vanilla/atom.ts'
import type { PrimitiveAtom } from '../src/vanilla/atom.ts'
import { createStore } from '../src/vanilla/store.ts'

const __dirname = path.dirname(fileURLToPath(import.meta.url))

const createStateWithAtoms = (n: number) => {
  let targetAtom: PrimitiveAtom<number> | undefined
  const store = createStore()
  for (let i = 0; i < n; ++i) {
    const a = atom(i)
    if (!targetAtom) {
      targetAtom = a
    }
    store.set(a, i)
  }
  if (!targetAtom) {
    throw new Error()
  }
  return [store, targetAtom] as const
}

const main = async () => {
  await suite(
    'simple-read',
    ...[2, 3, 4, 5, 6].map((n) =>
      add(`atoms=${10 ** n}`, () => {
        const [store, targetAtom] = createStateWithAtoms(10 ** n)
        return () => store.get(targetAtom)
      }),
    ),
    cycle(),
    complete(),
    save({
      folder: __dirname,
      file: 'simple-read',
      format: 'json',
    }),
    save({
      folder: __dirname,
      file: 'simple-read',
      format: 'chart.html',
    }),
  )
}

main()


================================================
FILE: benchmarks/simple-write.ts
================================================
#!/usr/bin/env npx tsx

/// <reference types="node" />

import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { add, complete, cycle, save, suite } from 'benny'
import { atom } from '../src/vanilla/atom.ts'
import type { PrimitiveAtom } from '../src/vanilla/atom.ts'
import { createStore } from '../src/vanilla/store.ts'

const __dirname = path.dirname(fileURLToPath(import.meta.url))

const createStateWithAtoms = (n: number) => {
  let targetAtom: PrimitiveAtom<number> | undefined
  const store = createStore()
  for (let i = 0; i < n; ++i) {
    const a = atom(i)
    if (!targetAtom) {
      targetAtom = a
    }
    store.set(a, i)
  }
  if (!targetAtom) {
    throw new Error()
  }
  return [store, targetAtom] as const
}

const main = async () => {
  await suite(
    'simple-write',
    ...[2, 3, 4, 5, 6].map((n) =>
      add(`atoms=${10 ** n}`, () => {
        const [store, targetAtom] = createStateWithAtoms(10 ** n)
        return () => store.set(targetAtom, (c) => c + 1)
      }),
    ),
    cycle(),
    complete(),
    save({
      folder: __dirname,
      file: 'simple-write',
      format: 'json',
    }),
    save({
      folder: __dirname,
      file: 'simple-write',
      format: 'chart.html',
    }),
  )
}

main()


================================================
FILE: benchmarks/subscribe-write.ts
================================================
#!/usr/bin/env npx tsx

/// <reference types="node" />

import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { add, complete, cycle, save, suite } from 'benny'
import { atom } from '../src/vanilla/atom.ts'
import type { PrimitiveAtom } from '../src/vanilla/atom.ts'
import { createStore } from '../src/vanilla/store.ts'

const __dirname = path.dirname(fileURLToPath(import.meta.url))

const cleanupFns = new Set<() => void>()
const cleanup = () => {
  cleanupFns.forEach((fn) => fn())
  cleanupFns.clear()
}

const createStateWithAtoms = (n: number) => {
  let targetAtom: PrimitiveAtom<number> | undefined
  const store = createStore()
  for (let i = 0; i < n; ++i) {
    const a = atom(i)
    if (!targetAtom) {
      targetAtom = a
    }
    store.get(a)
    const unsub = store.sub(a, () => {
      store.get(a)
    })
    cleanupFns.add(unsub)
  }
  if (!targetAtom) {
    throw new Error()
  }
  return [store, targetAtom] as const
}

const main = async () => {
  await suite(
    'subscribe-write',
    ...[2, 3, 4, 5, 6].map((n) =>
      add(`atoms=${10 ** n}`, () => {
        cleanup()
        const [store, targetAtom] = createStateWithAtoms(10 ** n)
        return () => store.set(targetAtom, (c) => c + 1)
      }),
    ),
    cycle(),
    complete(),
    save({
      folder: __dirname,
      file: 'subscribe-write',
      format: 'json',
    }),
    save({
      folder: __dirname,
      file: 'subscribe-write',
      format: 'chart.html',
    }),
  )
}

main()


================================================
FILE: docs/basics/comparison.mdx
================================================
---
title: Comparison
nav: 7.02
---

Jotai was born to solve extra re-render issues in React.
An extra re-render is when the render process produces the same UI result,
where users won't see any differences.

To tackle this issue with React context (useContext + useState),
one would require many contexts and face some issues.

- Provider hell: It's likely that your root component has many context providers, which is technically okay, and sometimes desirable to provide context in different subtree.
- Dynamic addition/deletion: Adding a new context at runtime is not very nice, because you need to add a new provider and its children will be re-mounted.

Traditionally, a top-down solution to this is to use a selector function.
The [use-context-selector](https://github.com/dai-shi/use-context-selector) library is one example.
The issue with this approach is the selector function needs to return
referentially equal values to prevent re-renders, and this often requires a memoization technique.

Jotai takes a bottom-up approach with the atomic model, inspired by [Recoil](https://recoiljs.org/).
One can build state combining atoms, and optimize renders based on atom dependency.
This avoids the need for memoization.

Jotai has two principles.

- Primitive: Its basic API is simple, like `useState`.
- Flexible: Atoms can derive another atom and form a graph. Atoms can also be updated by another arbitrary atom. It allows abstracting complex state models.

### How is Jotai different from useContext of React?

Jotai's core API is minimalistic and makes it easy to build utilities based upon it.

#### Analogy

You can view Jotai as a drop-in replacement to `useContext`. Except Jotai is aiming for simplicity, minimalistic API and can do much more than `useContext` & `useState`.

#### Usage difference

We can see how we used to share data to children, compared to how we do it with Jotai. But let's use a real-world example where we have multiple `Context` in our app.

```jsx
// 1. useState local state
const Component = () => {
  const [state, setState] = useState(0)
}

// 2. Lift local state up and share it via context
const StateContext = createContext()
const Parent = ({ children }) => {
  return (
    <StateContext.Provider value={useState(0)}>
      {children}
    </StateContext.Provider>
  )
}
const Component = () => {
  const [state, setState] = useContext(StateContext)
}

// 3. Have multiple states and contexts
const State1Context = createContext()
const State2Context = createContext()
const Parent = ({ children }) => (
  <State1Context.Provider value={useState(0)}>
    <State2Context.Provider value={useState(0)}>
      {children}
    </State2Context.Provider>
  </State1Context.Provider>
)
const Component1 = () => {
  const [state, setState] = useContext(State1Context)
}
const Component2 = () => {
  const [state, setState] = useContext(State2Context)
}
```

Now let's see how Jotai simplify it for us. You can just use atoms instead of multiple `Context`.

```jsx
import { Provider, atom, useAtom } from 'jotai'
const atom1 = atom(0)
const atom2 = atom(0)
// Optional: you can use Provider's just like useContext,
// ...but if you only need one,
// ...you can just omit it and Jotai will use a default one (called Provider-less mode).
const Parent = ({ children }) => {
  return <Provider>{children}</Provider>
}
const Component1 = () => {
  const [state, setState] = useAtom(atom1)
}
const Component2 = () => {
  const [state, setState] = useAtom(atom2)
}
```

### How is Jotai different from Zustand?

#### Name

Jotai means "state" in Japanese.
Zustand means "state" in German.

#### Analogy

Jotai is like Recoil.
Zustand is like Redux.

#### Where state resides

To hold states,
Both have stores that can exist either at module level or at context level.
Jotai is designed to be context first, and module second.
Zustand is designed to be module first, and context second.

#### How to structure state

Jotai state consists of atoms (i.e. bottom-up).
Zustand state is one object (i.e. top-down).

#### Technical difference

The major difference is the state model. Zustand is a single store (although you could create multiple separate stores), while Jotai consists of primitive atoms and allows composing them together. In this sense, it's the matter of programming mental model.

#### When to use which

- If you need a replacement for useState+useContext, Jotai fits well.
- If you want a simple module state, Zustand fits well.
- If code splitting is important, Jotai should perform well.
- If you prefer Redux devtools, Zustand is good to go.
- If you want to make use of Suspense, Jotai is the one.

### How is Jotai different from Recoil?

(Disclaimer: the author is not very familiar with Recoil, this may be biased and inaccurate.)

#### Developer

- Jotai is developed with collective work by a few developers in Poimandres (formerly react-spring) org.
- Recoil is developed by a team at Facebook.

#### Basis

- Jotai is focusing on primitive APIs for easy learning, and it's unopinionated. (The same philosophy with Zustand)
- Recoil is all-in-one, and it has various cache strategies.

#### Technical difference

- Jotai depends on atom object referential identities.
- Recoil depends on atom string keys.

#### When to use which

- If you want to learn something new, either should work.
- If you like Zustand, Jotai would also be pleasant.
- If you need React Context alternatives, Jotai comes with enough features.
- If you need to read and write atoms outside React, Jotai provides store API.
- If you would try to create a new library, Jotai might give good primitives.
- Otherwise, both are pretty similar about the general goals and basic techniques, so please try both and share your feedback with us.


================================================
FILE: docs/basics/concepts.mdx
================================================
---
title: Concepts
nav: 7.01
---

Jotai is a library that will make you return to the basics of React development & keep everything simple.

### From scratch

Before trying to compare Jotai with what we may have known previously, let's just dive straight into something very simple.

The React world is very much like our world, it's a big set of small entities, we call them components, and we know that they have their own state. Structuring your components to interact altogether will create your app.

Now, the Jotai world also has its small entities, atoms, and they also have their state. Composing atoms will create your app state!

Jotai considers anything to be an atom, so you may say: `Huh, I need objects and arrays, filter them and then sort them out`.
And here's the beauty of it, Jotai gracefully lets you create dumb atoms derived from even more dumb atoms.

If, for example, I have a page with 2 tabs: online friends and offline friends.
I will have 2 atoms simply derived from a common, dumber source.

```js
const dumbAtom = atom([{ name: 'Friend 1', online: false }])
const onlineAtom = atom((get) => get(dumbAtom).filter((item) => item.online))
const offlineAtom = atom((get) => get(dumbAtom).filter((item) => !item.online))
```

And you could keep going on complexity forever.

Another incredible feature of Jotai is the built-in ability to suspend when using asynchronous atoms. This is a relatively new feature that needs more experimentation, but is definitely the future of how we will build React apps. [Check out the docs](https://react.dev/blog/2022/03/29/react-v18#new-suspense-features) for more info.


================================================
FILE: docs/basics/functional-programming-and-jotai.mdx
================================================
---
title: Functional programming and Jotai
nav: 7.04
---

### Unexpected similarities

If you look at getter functions long enough, you may see a striking resemblance
to a certain JavaScript language feature.

```tsx
const nameAtom = atom('Visitor')
const countAtom = atom(1)
const greetingAtom = atom((get) => {
  const name = get(nameAtom)
  const count = get(countAtom)
  return (
    <div>
      Hello, {name}! You have visited this page {count} times.
    </div>
  )
})
```

Compare that code with `async`–`await`:

```tsx
const namePromise = Promise.resolve('Visitor')
const countPromise = Promise.resolve(1)
const greetingPromise = (async function () {
  const name = await namePromise
  const count = await countPromise
  return (
    <div>
      Hello, {name}! You have visited this page {count} times.
    </div>
  )
})()
```

This similarity is no coincidence. Both atoms and promises are **Monads**†, a
concept from functional programming. The syntax used in both `greetingAtom` and
`greetingPromise` is known as **do-notation**, a syntax sugar for the plainer
monad interface.

### About monads

The monad interface is responsible for the fluidity of the atom and promise
interfaces. The monad interface allowed us to define `greetingAtom` in terms of
`nameAtom` and `countAtom`, and allowed us to define `greetingPromise` in terms
of `namePromise` and `countPromise`.

If you're curious, a structure (like `Atom` or `Promise`) is a monad if you can
implement the following functions for it. A fun exercise is trying to implement
`of`, `map` and `join` for Arrays.

```ts
type SomeMonad<T> = /* for example... */ Array<T>
declare function of<T>(plainValue: T): SomeMonad<T>
declare function map<T, V>(
  anInstance: SomeMonad<T>,
  transformContents: (contents: T) => V,
): SomeMonad<V>
declare function join<T>(nestedInstances: SomeMonad<SomeMonad<T>>): SomeMonad<T>
```

The shared heritage of Promises and Atoms means many patterns and best-practices
can be reused between them. Let's take a look at one.

### Sequencing

When talking about callback hell, we often mention the boilerplate, the
indentation and the easy-to-miss mistakes. However, plumbing a single async
operation into another single async operation was not the end of the callback
struggle. What if we made four network calls and needed to wait for them all?
A snippet like this was common:

```ts
const nPending = 4
const results: string[]
function callback(err, data) {
  if (err) throw err
  results.push(data)
  if (results.length === nPending) {
    // do something with results...
  }
}
```

But what if the results have different types? and the order was important? Well,
we'd have a lot more frustrating work to do! This logic would be duplicated at
each usage, and would be easy to mess up. Since ES6, we simply call `Promise.all`:

```ts
declare function promiseAll<T>(promises: Array<Promise<T>>): Promise<Array<T>>
```

`Promise.all` "rearranges" `Array` and `Promise`. It turns out this concept,
_sequencing_, can be implemented for all monad–_Traversable_ pairs. Many kinds
of collections are Traversables, including Arrays. For example, this is a case
of sequencing specialized for atoms and arrays:

```ts
function sequenceAtomArray<T>(atoms: Array<Atom<T>>): Atom<Array<T>> {
  return atom((get) => atoms.map(get))
}
```

### Culmination

Monads have been an interest to mathematicians for 60 years, and to programmers
for 40. There are many resources out there on patterns for monads. Take a look
at them! Here are a select few:

- [_Inventing Monads_](https://stopa.io/post/247) by Stepan Parunashvili
- [_How Monads Solve Problems_](https://thatsnomoon.dev/posts/ts-monads/) by ThatsNoMoon
- Wiki page [list of monad tutorials](https://wiki.haskell.org/Monad_tutorials_timeline)
- [Typeclassopedia](https://wiki.haskell.org/Typeclassopedia) (for the curious)

Learning a neat trick on using promises may well translate to atoms, as
`Promise.all` and `sequenceAtomArray` did. Monads are not magic, just unusually
useful, and a tool worth knowing.

---

_Notes_

**[†]** The ES6 Promise is not a completely valid monad because it cannot nest other
Promises, e.g. `Promise<Promise<number>>` is semantically equivalent to
`Promise<number>`. This is why Promises only have a `.then`, and not both a
`.map` and `.flatMap`. ES6 Promises are probably more properly described as
"monadic" rather than as monads.

Unlike ES6 Promises, the ES6 Array is a completely lawful monad.


================================================
FILE: docs/basics/showcase.mdx
================================================
---
title: Showcase
nav: 7.03
---

- Text Length example [![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-CodeSandbox-blue?style=flat-square&logo=codesandbox)](https://githubbox.com/pmndrs/jotai/tree/main/examples/text_length)

  Count the length and show the uppercase of any text.

- Hacker News example [![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-CodeSandbox-blue?style=flat-square&logo=codesandbox)](https://githubbox.com/pmndrs/jotai/tree/main/examples/hacker_news)

  Demonstrate a news article with Jotai, hit next to see more articles.

- Todos example [![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-CodeSandbox-blue?style=flat-square&logo=codesandbox)](https://githubbox.com/pmndrs/jotai/tree/main/examples/todos)

  Record your todo list by typing them into this app, check them off if you have completed the task, and switch between `Completed` and `Incompleted` to see the status of your task.

- Todos example with atomFamily and localStorage [![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-CodeSandbox-blue?style=flat-square&logo=codesandbox)](https://githubbox.com/pmndrs/jotai/tree/main/examples/todos_with_atomFamily)

  Implement a todo list using atomFamily and localStorage. You can store your todo list to localStorage by clicking `Save to localStorage`, then remove your todo list and try restoring them by clicking `Load from localStorage`.

- Clock with Next.js [![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-CodeSandbox-blue?style=flat-square&logo=codesandbox)](https://codesandbox.io/s/nextjs-with-jotai-5ylrj)

  An UTC time electronic clock implementation using Next.js and Jotai.

- Tic Tac Toe game [![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-CodeSandbox-blue?style=flat-square&logo=codesandbox)](https://codesandbox.io/s/jotai-tic-tac-6cg3h)

  A game of tic tac toe implemented with Jotai.

- React Three Fiber demo [![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-CodeSandbox-blue?style=flat-square&logo=codesandbox)](https://codesandbox.io/s/jotai-r3f-fri9d)

  A simple demo to use Jotai with react-three-fiber


================================================
FILE: docs/core/atom.mdx
================================================
---
title: atom
description: This doc describes core `jotai` bundle.
nav: 2.01
keywords: atom,primitive,derived,debug,label,onmount
---

## atom

The `atom` function is to create an atom config.
We call it "atom config" as it's just a definition and it doesn't yet hold a value.
We may also call it just "atom" if the context is clear.

An atom config is an immutable object. The atom config object doesn't hold a value. The atom value exists in a store.

To create a primitive atom (config), all you need is to provide an initial value.

```js
import { atom } from 'jotai'

const priceAtom = atom(10)
const messageAtom = atom('hello')
const productAtom = atom({ id: 12, name: 'good stuff' })
```

You can also create derived atoms. We have three patterns:

- Read-only atom
- Write-only atom
- Read-Write atom

To create derived atoms, we pass a read function and an optional write function.

```js
const readOnlyAtom = atom((get) => get(priceAtom) * 2)
const writeOnlyAtom = atom(
  null, // it's a convention to pass `null` for the first argument
  (get, set, update) => {
    // `update` is any single value we receive for updating this atom
    set(priceAtom, get(priceAtom) - update.discount)
    // or we can pass a function as the second parameter
    // the function will be invoked,
    //  receiving the atom's current value as its first parameter
    set(priceAtom, (price) => price - update.discount)
  },
)
const readWriteAtom = atom(
  (get) => get(priceAtom) * 2,
  (get, set, newPrice) => {
    set(priceAtom, newPrice / 2)
    // you can set as many atoms as you want at the same time
  },
)
```

`get` in the read function is to read the atom value.
It's reactive and read dependencies are tracked.

`get` in the write function is also to read atom value, but it's not tracked.
Furthermore, it can't read unresolved async values in Jotai v1 API.

`set` in the write function is to write atom value.
It will invoke the write function of the target atom.

### Note about creating an atom in render function

Atom configs can be created anywhere, but referential equality is important.
They can be created dynamically too.
To create an atom in render function, `useMemo` or `useRef` is required to get a stable reference. If in doubt about using `useMemo` or `useRef` for memoization, use `useMemo`.
Otherwise, it can cause infinite loop with `useAtom`.

```js
const Component = ({ value }) => {
  const valueAtom = useMemo(() => atom({ value }), [value])
  // ...
}
```

### Signatures

```ts
// primitive atom
function atom<Value>(initialValue: Value): PrimitiveAtom<Value>

// read-only atom
function atom<Value>(read: (get: Getter) => Value): Atom<Value>

// writable derived atom
function atom<Value, Args extends unknown[], Result>(
  read: (get: Getter) => Value,
  write: (get: Getter, set: Setter, ...args: Args) => Result,
): WritableAtom<Value, Args, Result>

// write-only derived atom
function atom<Value, Args extends unknown[], Result>(
  read: Value,
  write: (get: Getter, set: Setter, ...args: Args) => Result,
): WritableAtom<Value, Args, Result>
```

- `initialValue`: the initial value that the atom will return until its value is changed.
- `read`: a function that's evaluated whenever the atom is read. The signature of `read` is `(get) => Value`, and `get` is a function that takes an atom config and returns its value stored in Provider as described below. Dependency is tracked, so if `get` is used for an atom at least once, the `read` will be reevaluated whenever the atom value is changed.
- `write`: a function mostly used for mutating atom's values, for a better description; it gets called whenever we call the second value of the returned pair of `useAtom`, the `useAtom()[1]`. The default value of this function in the primitive atom will change the value of that atom. The signature of `write` is `(get, set, ...args) => Result`. `get` is similar to the one described above, but it doesn't track the dependency. `set` is a function that takes an atom config and a new value which then updates the atom value in Provider. `...args` is the arguments that we receive when we call `useAtom()[1]`. `Result` is the return value of the `write` function.

```js
const primitiveAtom = atom(initialValue)
const derivedAtomWithRead = atom(read)
const derivedAtomWithReadWrite = atom(read, write)
const derivedAtomWithWriteOnly = atom(null, write)
```

There are two kinds of atoms: a writable atom and a read-only atom. Primitive atoms are always writable. Derived atoms are writable if the `write` is specified. The `write` of primitive atoms is equivalent to the `setState` of `React.useState`.

### `debugLabel` property

The created atom config can have an optional property `debugLabel`. The debug label is used to display the atom in debugging. See [Debugging guide](../guides/debugging.mdx) for more information.

Note: While, the debug labels don’t have to be unique, it’s generally recommended to make them distinguishable.

### `onMount` property

The created atom config can have an optional property `onMount`. `onMount` is a function which takes a function `setAtom` and returns `onUnmount` function optionally.

The `onMount` function is called when the atom is subscribed in the provider in the first time,
and `onUnmount` is called when it’s no longer subscribed.
In some cases (like [React strict mode](https://react.dev/reference/react/StrictMode)),
an atom can be unmounted and then mounted immediately.

```js
const anAtom = atom(1)
anAtom.onMount = (setAtom) => {
  console.log('atom is mounted in provider')
  setAtom(c => c + 1) // increment count on mount
  return () => { ... } // return optional onUnmount function
}

const Component = () => {
  // `onMount` will be called when the component is mounted in the following cases:
  useAtom(anAtom)
  useAtomValue(anAtom)

  // however, in the following cases,
  //  `onMount` will not be called because the atom is not subscribed:
  useSetAtom(anAtom)
  useAtomCallback(
    useCallback((get) => get(anAtom), []),
  )
  // ...
}
```

Calling `setAtom` function will invoke the atom’s `write`. Customizing `write` allows changing the behavior.

```js
const countAtom = atom(1)
const derivedAtom = atom(
  (get) => get(countAtom),
  (get, set, action) => {
    if (action.type === 'init') {
      set(countAtom, 10)
    } else if (action.type === 'inc') {
      set(countAtom, (c) => c + 1)
    }
  },
)
derivedAtom.onMount = (setAtom) => {
  setAtom({ type: 'init' })
}
```

### Advanced API

Since Jotai v2, the `read` function has the second argument `options`.

#### `options.signal`

It uses [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) so that you can abort async functions.
Abort is triggered before new calculation (invoking `read` function) is started.

How to use it:

```ts
const readOnlyDerivedAtom = atom(async (get, { signal }) => {
  // use signal to abort your function
})

const writableDerivedAtom = atom(
  async (get, { signal }) => {
    // use signal to abort your function
  },
  (get, set, arg) => {
    // ...
  },
)
```

The `signal` value is [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal).
You can check `signal.aborted` boolean value, or use `abort` event with `addEventListener`.

For `fetch` use case, we can simply pass `signal`.

See the below example for `fetch` usage.

#### `options.setSelf`

It's a special function to invoke the write function of the self atom.

⚠️ It's provided primarily for internal usage and third-party library authors. Read the source code carefully to understand the behavior. Check release notes for any breaking/non-breaking changes.

## Stackblitz

<Stackblitz id="vitejs-vite-ccqxix" file="src%2FApp.tsx" />

```tsx
import { Suspense } from 'react'
import { atom, useAtom } from 'jotai'

const userIdAtom = atom(1)
const userAtom = atom(async (get, { signal }) => {
  const userId = get(userIdAtom)
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/users/${userId}?_delay=2000`,
    { signal },
  )
  return response.json()
})

const Controls = () => {
  const [userId, setUserId] = useAtom(userIdAtom)
  return (
    <div>
      User Id: {userId}
      <button onClick={() => setUserId((c) => c - 1)}>Prev</button>
      <button onClick={() => setUserId((c) => c + 1)}>Next</button>
    </div>
  )
}

const UserName = () => {
  const [user] = useAtom(userAtom)
  return <div>User name: {user.name}</div>
}

const App = () => (
  <>
    <Controls />
    <Suspense fallback="Loading...">
      <UserName />
    </Suspense>
  </>
)

export default App
```


================================================
FILE: docs/core/provider.mdx
================================================
---
title: Provider
description: This doc describes core `jotai` bundle.
nav: 2.04
keywords: provider,usestore,ssr
---

## Provider

The `Provider` component is to provide state for a component sub tree.
Multiple Providers can be used for multiple subtrees, and they can even be nested.
This works just like React Context.

If an atom is used in a tree without a Provider,
it will use the default state. This is so-called provider-less mode.

Providers are useful for three reasons:

1. To provide a different state for each sub tree.
2. To accept initial values of atoms.
3. To clear all atoms by remounting.

```jsx
const SubTree = () => (
  <Provider>
    <Child />
  </Provider>
)
```

### Signatures

```ts
const Provider: React.FC<{
  store?: Store
}>
```

Atom configs don't hold values. Atom values reside in separate stores. A Provider is a component that contains a store and provides atom values under the component tree. A Provider works like React context provider. If you don't use a Provider, it works as provider-less mode with a default store. A Provider will be necessary if we need to hold different atom values for different component trees. Provider can take an optional prop `store`.

```jsx
const Root = () => (
  <Provider>
    <App />
  </Provider>
)
```

### `store` prop

A Provider accepts an optional prop `store` that you can use for the Provider subtree.

#### Example

```jsx
const myStore = createStore()

const Root = () => (
  <Provider store={myStore}>
    <App />
  </Provider>
)
```

## useStore

This hook returns a store within the component tree.

```jsx
const Component = () => {
  const store = useStore()
  // ...
}
```


================================================
FILE: docs/core/store.mdx
================================================
---
title: Store
description: This doc describes core `jotai` bundle.
nav: 2.03
keywords: store,createstore,getdefaultstore,defaultstore
---

## createStore

This function is to create a new empty store.
The store can be used to pass in `Provider`.

The store has three methods: `get` for getting atom values,
`set` for setting atom values, and `sub` for subscribing to atom changes.

```jsx
const myStore = createStore()

const countAtom = atom(0)
myStore.set(countAtom, 1)
const unsub = myStore.sub(countAtom, () => {
  console.log('countAtom value is changed to', myStore.get(countAtom))
})
// unsub() to unsubscribe

const Root = () => (
  <Provider store={myStore}>
    <App />
  </Provider>
)
```

## getDefaultStore

This function returns a default store that is used in provider-less mode.

```js
const defaultStore = getDefaultStore()
```


================================================
FILE: docs/core/use-atom.mdx
================================================
---
title: useAtom
description: This doc describes core `jotai` bundle.
nav: 2.02
keywords: use,useatom,useatomvalue,usesetatom,atomvalue,setatom
---

## useAtom

The `useAtom` hook is used to read an atom from the state.
The state can be seen as a WeakMap of atom configs and atom values.

The `useAtom` hook returns the atom value and an update function as a tuple,
just like React's `useState`.
It takes an atom config created with `atom()` as a parameter.

At the creation of the atom config, there is no value associated with it.
Only once the atom is used via `useAtom`, does the initial value get stored in the state.
If the atom is a derived atom, the read function is called to compute its initial value.
When an atom is no longer used, meaning all the components using it are unmounted
and the atom config no longer exists, the value in the state is garbage collected.

```js
const [value, setValue] = useAtom(anAtom)
```

The `setValue` takes just one argument, which will be passed
to the write function of the atom as the third parameter.
The end result depends on how the write function is implemented.
If the write function is not explicitly set, the atom will simply receive the value passed as a parameter to `setValue`.

**Note:** as mentioned in the _atom_ section, referential equality is important when creating atoms,
so you need to handle it properly otherwise it can cause infinite loops.

```js
const stableAtom = atom(0)
const Component = () => {
  const [atomValue] = useAtom(atom(0)) // This will cause an infinite loop since the atom instance is being recreated in every render
  const [atomValue] = useAtom(stableAtom) // This is fine
  const [derivedAtomValue] = useAtom(
    useMemo(
      // This is also fine
      () => atom((get) => get(stableAtom) * 2),
      [],
    ),
  )
}
```

**Note**: Remember that React is responsible for calling your component, meaning it has to be idempotent, ready to be called multiple times. You will often see an extra re-render even if no props or atoms have changed. An extra re-render without a commit is an expected behavior, since it is the default behavior of useReducer in React 18.

### Signatures

```ts
// primitive or writable derived atom
function useAtom<Value, Update>(
  atom: WritableAtom<Value, Update>,
  options?: { store?: Store },
): [Value, SetAtom<Update>]

// read-only atom
function useAtom<Value>(
  atom: Atom<Value>,
  options?: { store?: Store },
): [Value, never]
```

### How atom dependency works

Every time we invoke the "read" function, we refresh the dependencies and dependents.

> The read function is the first parameter of the atom.
> If B depends on A, it means that A is a dependency of B, and B is a dependent on A.

```js
const uppercaseAtom = atom((get) => get(textAtom).toUpperCase())
```

When you create the atom, the dependency will not be present. On first use, we run the read function and conclude that `uppercaseAtom` depends on `textAtom`. So `uppercaseAtom` is added to the dependents of `textAtom`.
When we re-run the read function of `uppercaseAtom` (because its `textAtom` dependency is updated),
the dependency is created again, which is the same in this case. We then remove stale dependents from `textAtom` and replace them with their latest versions.

### Atoms can be created on demand

While the basic examples here show defining atoms globally outside components,
there's no restrictions about where or when we can create an atom.
As long as we remember that atoms are identified by their object referential identity,
we can create them anytime.

If you create atoms in render functions, you would typically want to use
a hook like `useRef` or `useMemo` for memoization. If not, the atom would be re-created each time the component renders.

You can create an atom and store it with `useState` or even in another atom.
See an example in [issue #5](https://github.com/pmndrs/jotai/issues/5).

You can also cache atoms somewhere globally.
See [this example](https://twitter.com/dai_shi/status/1317653548314718208) or
[that example](https://github.com/pmndrs/jotai/issues/119#issuecomment-706046321).

Check [`atomFamily`](../utilities/family.mdx) in utils for parameterized atoms.

## useAtomValue

```jsx
const countAtom = atom(0)

const Counter = () => {
  const setCount = useSetAtom(countAtom)
  const count = useAtomValue(countAtom)

  return (
    <>
      <div>count: {count}</div>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </>
  )
}
```

Similar to the `useSetAtom` hook, `useAtomValue` allows you to access a read-only atom. Nonetheless, it can also be used to access read-write atom's values.

## useSetAtom

```jsx
const switchAtom = atom(false)

const SetTrueButton = () => {
  const setCount = useSetAtom(switchAtom)
  const setTrue = () => setCount(true)

  return (
    <div>
      <button onClick={setTrue}>Set True</button>
    </div>
  )
}

const SetFalseButton = () => {
  const setCount = useSetAtom(switchAtom)
  const setFalse = () => setCount(false)

  return (
    <div>
      <button onClick={setFalse}>Set False</button>
    </div>
  )
}

export default function App() {
  const state = useAtomValue(switchAtom)

  return (
    <div>
      State: <b>{state.toString()}</b>
      <SetTrueButton />
      <SetFalseButton />
    </div>
  )
}
```

In case you need to update a value of an atom without reading it, you can use `useSetAtom()`.

This is especially useful when the performance is a concern, as the `const [, setValue] = useAtom(valueAtom)` will cause unnecessary rerenders on each `valueAtom` update.


================================================
FILE: docs/extensions/cache.mdx
================================================
---
title: Cache
description: This doc describes cache extension.
nav: 4.07
keywords: cache
---

Jotai provides primitive functions to optimize re-renders.
It's designed to hold only "current" atom values,
and it doesn't cache older values.

Caching is sometimes useful. For example, if an async atom
triggers network requests, we may want to cache the responses.

[jotai-cache](https://github.com/jotai-labs/jotai-cache) is
a third-party library to help such use cases.

### Install

```
npm install jotai-cache
```

## atomWithCache

```js
atomWithCache(read, options): Atom
```

`atomWithCache` creates a new read-only atom with cache.

### Parameters

**read**: read function to define the read-only atom.

**options** (optional): an object of options to customize the behavior of the atom

### Options

**size** (optional): maximum size of cache items.

**shouldRemove** (optional): a function to check if cache items should be removed.

**areEqual** (optional): a function to compare atom values.

### Examples

```jsx
import { atom, useAtom } from 'jotai'
import { atomWithCache } from 'jotai-cache'

const idAtom = atom(1)

const normalAtom = atom(async (get) => {
  const id = get(idAtom)
  const response = await fetch(`https://reqres.in/api/users/${id}?delay=1`)
  return response.json()
})

const cachedAtom = atomWithCache(async (get) => {
  const id = get(idAtom)
  const response = await fetch(`https://reqres.in/api/users/${id}?delay=1`)
  return response.json()
})

const NormalUser = () => {
  const [{ data }] = useAtom(normalAtom)
  return (
    <div>
      <h1>User (normal atom)</h1>
      <ul>
        <li>ID: {data.id}</li>
        <li>First name: {data.first_name}</li>
        <li>Last name: {data.last_name}</li>
      </ul>
    </div>
  )
}

const CachedUser = () => {
  const [{ data }] = useAtom(cachedAtom)
  return (
    <div>
      <h1>User (cached atom)</h1>
      <ul>
        <li>ID: {data.id}</li>
        <li>First name: {data.first_name}</li>
        <li>Last name: {data.last_name}</li>
      </ul>
    </div>
  )
}

const App = () => {
  const [id, setId] = useAtom(idAtom)
  return (
    <div>
      ID: {id}{' '}
      <button type="button" onClick={() => setId((c) => c - 1)}>
        Prev
      </button>{' '}
      <button type="button" onClick={() => setId((c) => c + 1)}>
        Next
      </button>
      <hr />
      <Suspense fallback="Loading...">
        <CachedUser />
      </Suspense>
      <hr />
      <Suspense fallback="Loading...">
        <NormalUser />
      </Suspense>
    </div>
  )
}
```

### Stackblitz

<Stackblitz id="vitejs-vite-p86ajq" file="src%2FApp.tsx" />


================================================
FILE: docs/extensions/effect.mdx
================================================
---
title: Effect
description: A Jōtai utility package for reactive side effects
nav: 4.03
keywords: effect, atom effect, side effect, side-effect, sideeffect
---

[jotai-effect](https://github.com/jotaijs/jotai-effect) is a utility package for reactive side effects in Jotai.

## Install

```
npm install jotai-effect
```

## observe

`observe` mounts an `effect` to watch state changes on a Jotai `store`. It's useful for running global side effects or logic at the store level.

If you don't have access to the store object and are not using the default store, use `atomEffect` or `withAtomEffect` instead.

### Signature

```ts
type Cleanup = () => void

type Effect = (
  get: Getter & { peek: Getter }
  set: Setter & { recurse: Setter }
) => Cleanup | void

type Unobserve = () => void

function observe(effect: Effect, store?: Store): Unobserve
```

**effect:** A function for observing and reacting to atom state changes.

**store:** A Jotai store to mount the effect on. Defaults to the global store if not provided.

**returns:** A stable function that removes the effect from the store and cleans up any internal references.

### Usage

```js
import { observe } from 'jotai-effect'

const unobserve = observe((get, set) => {
  set(logAtom, `someAtom changed: ${get(someAtom)}`)
})

unobserve()
```

This allows you to run Jotai state-dependent logic outside React's lifecycle, ideal for application-wide effects.

### Usage With React

Pass the store to both `observe` and the `Provider` to ensure the effect is mounted to the correct store.

```tsx
const store = createStore()
const unobserve = observe((get, set) => {
  set(logAtom, `someAtom changed: ${get(someAtom)}`)
}, store)

<Provider store={store}>...</Provider>
```

<Stackblitz id="vitejs-vite-uk7p8i5q" file="src%2FApp.tsx" />

## atomEffect

`atomEffect` creates an atom for declaring side effects that react to state changes when mounted.

### Signature

```ts
function atomEffect(effect: Effect): Atom<void>
```

**effect:** A function for observing and reacting to atom state changes.

### Usage

```js
import { atomEffect } from 'jotai-effect'

const logEffect = atomEffect((get, set) => {
  set(logAtom, get(someAtom)) // Runs on mount or when someAtom changes
  return () => {
    set(logAtom, 'unmounting') // Cleanup on unmount
  }
})

// activates the atomEffect while Component is mounted
function Component() {
  useAtom(logEffect)
}
```

## withAtomEffect

`withAtomEffect` binds an effect to a clone of the target atom. The effect is active while the cloned atom is mounted.

### Signature

```ts
function withAtomEffect<T>(targetAtom: Atom<T>, effect: Effect): Atom<T>
```

**targetAtom:** The atom to which the effect is bound.

**effect:** A function for observing and reacting to atom state changes.

**Returns:** An atom that is equivalent to the target atom but having a bound effect.

### Usage

```js
import { withAtomEffect } from 'jotai-effect'

const valuesAtom = withAtomEffect(atom(null), (get, set) => {
  set(valuesAtom, get(countAtom))
  return () => {
    // cleanup
  }
})
```

## Dependency Management

Aside from mount events, the effect runs when any of its dependencies change value.

- **Sync:**
  All atoms accessed with `get` inside the effect are added to the atom's dependencies.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    // updates whenever `anAtom` changes value
    get(anAtom)
  })
  ```

  </details>

- **Async:**
  Asynchronous `get` calls do not add dependencies.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    setTimeout(() => {
      // does not add `anAtom` as a dependency
      get(anAtom)
    })
  })
  ```

  </details>

- **Cleanup:**
  `get` calls in cleanup do not add dependencies.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    return () => {
      // does not add `anAtom` as a dependency
      get(anAtom)
    }
  })
  ```

  </details>

- **Dependency Map Recalculation:**
  Dependencies are recalculated on every run.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    if (get(isEnabledAtom)) {
      // `isEnabledAtom` and `anAtom` are dependencies
      const aValue = get(anAtom)
    } else {
      // `isEnabledAtom` and `anotherAtom` are dependencies
      const anotherValue = get(anotherAtom)
    }
  })
  ```

  </details>

## Effect Behavior

- **Executes Synchronously:**
  `effect` runs synchronous in the current task after synchronous evaluations complete.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  const logCounts = atomEffect((get, set) => {
    set(logAtom, `count is ${get(countAtom)}`)
  })
  const actionAtom = atom(null, (get, set) => {
    get(logAtom) // 'count is 0'
    set(countAtom, (value) => value + 1) // effect runs synchronously
    get(logAtom) // 'count is 1'
  })
  store.sub(logCounts, () => {})
  store.set(actionAtom)
  ```

  </details>

- **Batched Updates:**
  Multiple synchronous updates are batched as a single atomic transaction.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  const tensAtom = atom(0)
  const onesAtom = atom(0)
  const updateTensAndOnes = atom(null, (get, set) => {
    set(tensAtom, (value) => value + 1)
    set(onesAtom, (value) => value + 1)
  })
  const combos = atom([])
  const effectAtom = atomEffect((get, set) => {
    const value = get(tensAtom) * 10 + get(onesAtom)
    set(combos, (arr) => [...arr, value])
  })
  store.sub(effectAtom, () => {})
  store.set(updateTensAndOnes)
  store.get(combos) // [00, 11]
  ```

  </details>

- **Resistant to Infinite Loops:**
  `atomEffect` avoids rerunning when it updates a value that it is watching.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    get(countAtom)
    set(countAtom, (value) => value + 1) // Will not loop
  })
  ```

  </details>

- **Cleanup Function:**
  The cleanup function is invoked on unmount or before re-evaluation.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    const intervalId = setInterval(() => set(clockAtom, Date.now()))
    return () => clearInterval(intervalId)
  })
  ```

  </details>

- **Idempotency:**
  `atomEffect` runs once per state change, regardless of how many times it is referenced.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  let i = 0
  const effectAtom = atomEffect(() => {
    get(countAtom)
    i++
  })
  store.sub(effectAtom, () => {})
  store.sub(effectAtom, () => {})
  store.set(countAtom, (value) => value + 1)
  console.log(i) // 1
  ```

  </details>

- **Conditionally Running Effects:**
  `atomEffect` only runs when mounted.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atom((get) => {
    if (get(isEnabledAtom)) {
      get(effectAtom)
    }
  })
  ```

  </details>

- **Supports Peek:**
  Use `get.peek` to read atom data without subscribing.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  const countAtom = atom(0)
  atomEffect((get, set) => {
    const count = get.peek(countAtom) // Will not add `countAtom` as a dependency
  })
  ```

  </details>

- **Supports Recursion:**
  Recursion is supported with `set.recurse` but not in cleanup.

  <!-- prettier-ignore -->
  <details style="cursor: pointer; user-select: none;">
    <summary>Example</summary>

  ```js
  atomEffect((get, set) => {
    const count = get(countAtom)
    if (count % 10 === 0) {
      return
    }
    set.recurse(countAtom, (value) => value + 1)
  })
  ```

  </details>


================================================
FILE: docs/extensions/immer.mdx
================================================
---
title: Immer
description: This doc describes Immer extension.
nav: 4.04
keywords: immer
---

### Install

You have to install `immer` and `jotai-immer` to use this feature.

```
npm install immer jotai-immer
```

## atomWithImmer

`atomWithImmer` creates a new atom similar to the regular [`atom`](../core/atom.mdx) with a different `writeFunction`. In this bundle, we don't have read-only atoms, because the point of these functions is the immer produce(mutability) function.
The signature of writeFunction is `(get, set, update: (draft: Draft<Value>) => void) => void`.

```jsx
import { useAtom } from 'jotai'
import { atomWithImmer } from 'jotai-immer'

const countAtom = atomWithImmer({ value: 0 })

const Counter = () => {
  const [count] = useAtom(countAtom)
  return <div>count: {count.value}</div>
}

const Controls = () => {
  const [, setCount] = useAtom(countAtom)
  // setCount === update : (draft: Draft<Value>) => void
  const inc = () =>
    setCount((draft) => {
      ++draft.value
    })
  return <button onClick={inc}>+1</button>
}
```

### Examples

Check this example with atomWithImmer:

<Stackblitz id="vitejs-vite-tblppw" file="src%2FApp.tsx" />

## withImmer

`withImmer` takes an atom and returns a derived atom, same as `atomWithImmer` it has a different `writeFunction`.

```jsx
import { useAtom, atom } from 'jotai'
import { withImmer } from 'jotai-immer'

const primitiveAtom = atom({ value: 0 })
const countAtom = withImmer(primitiveAtom)

const Counter = () => {
  const [count] = useAtom(countAtom)
  return <div>count: {count.value}</div>
}

const Controls = () => {
  const [, setCount] = useAtom(countAtom)
  // setCount === update : (draft: Draft<Value>) => void
  const inc = () =>
    setCount((draft) => {
      ++draft.value
    })
  return <button onClick={inc}>+1</button>
}
```

### Examples

Check this example with withImmer:

<Stackblitz id="vitejs-vite-jwfjqm" file="src%2FApp.tsx" />

## useImmerAtom

This hook takes an atom and replaces the atom's `writeFunction` with the new immer-like `writeFunction` like the previous helpers.

```jsx
import { atom } from 'jotai'
import { useImmerAtom } from 'jotai-immer'

const primitiveAtom = atom({ value: 0 })

const Counter = () => {
  const [count] = useImmerAtom(primitiveAtom)
  return <div>count: {count.value}</div>
}

const Controls = () => {
  const [, setCount] = useImmerAtom(primitiveAtom)
  // setCount === update : (draft: Draft<Value>) => void
  const inc = () =>
    setCount((draft) => {
      ++draft.value
    })
  return <button onClick={inc}>+1</button>
}
```

It would be better if you don't use `withImmer` and `atomWithImmer` with `useImmerAtom` because they provide the immer-like `writeFunction` and we don't need to create a new one.

You can use `useSetImmerAtom` if you need only the setter part of `useImmerAtom`.

### Examples

Check this example with useImmerAtom:

<Stackblitz id="vitejs-vite-k2rixl" file="src%2FApp.tsx" />

## Demo

<Stackblitz id="vitejs-vite-tksbwq" file="src%2FApp.tsx" />


================================================
FILE: docs/extensions/location.mdx
================================================
---
title: Location
description: This doc describes window.location extension.
nav: 4.06
keywords: location,hash
---

To deal with `window.location`, we have some functions to create atoms.

### Install

You have to install `jotai-location` to use this feature.

```
npm install jotai-location
```

## atomWithLocation

```js
atomWithLocation(options): PrimitiveAtom
```

`atomWithLocation` creates a new atom that links to `window.location`.

Typically, you should only instantiate `atomWithLocation` once per application. This is because changes made to one instance might not be reflected in others.
As this atom is designed to synchronize with the `window.location` object, using multiple instances can lead to unpredictable behavior.

### Parameters

**options** (optional): an object of options to customize the behavior of the atom

### Options

**preloaded** (optional): preloaded location value to avoid getting location at initialization.

**replace** (optional): a boolean to indicate to use `replaceState` instead of `pushState`.

**getLocation** (optional): a custom function to get location value.

**applyLocation** (optional): a custom function to set location value.

**subscribe** (optional): a custom function to subscribe to location change.

### Examples

```jsx
import { useAtom } from 'jotai'
import { atomWithLocation } from 'jotai-location'

const locationAtom = atomWithLocation()

const App = () => {
  const [loc, setLoc] = useAtom(locationAtom)
  return (
    <ul>
      <li>
        <button
          style={{
            fontWeight: loc.pathname === '/' ? 'bold' : 'normal',
          }}
          onClick={() => setLoc((prev) => ({ ...prev, pathname: '/' }))}
        >
          Home
        </button>
      </li>
      <li>
        <button
          style={{
            fontWeight:
              loc.pathname === '/foo' && !loc.searchParams?.get('bar')
                ? 'bold'
                : 'normal',
          }}
          onClick={() =>
            setLoc((prev) => ({
              ...prev,
              pathname: '/foo',
              searchParams: new URLSearchParams(),
            }))
          }
        >
          Foo
        </button>
      </li>
      <li>
        <button
          style={{
            fontWeight:
              loc.pathname === '/foo' && loc.searchParams?.get('bar') === '1'
                ? 'bold'
                : 'normal',
          }}
          onClick={() =>
            setLoc((prev) => ({
              ...prev,
              pathname: '/foo',
              searchParams: new URLSearchParams([['bar', '1']]),
            }))
          }
        >
          Foo?bar=1
        </button>
      </li>
    </ul>
  )
}
```

### Stackblitz

<Stackblitz id="vitejs-vite-9v72fq" file="src%2FApp.tsx" />

## atomWithHash

```js
atomWithHash(key, initialValue, options): PrimitiveAtom
```

This creates a new atom that is connected with URL hash.
The hash must be in the URLSearchParams format.
It's a two-way binding: changing the atom value will change the hash and
changing the hash will change the atom value.
This function works only with DOM.

### Parameters

**key** (required): a unique string used as the key when syncing state with localStorage, sessionStorage, or AsyncStorage

**initialValue** (required): the initial value of the atom

**options** (optional): an object of options to customize the behavior of the atom

### Options

**serialize** (optional): a custom function to serialize the atom value to the hash. Defaults to `JSON.stringify`.

**deserialize** (optional): a custom function to deserialize the hash to the atom value. Defaults to `JSON.parse`.

**subscribe** (optional): custom hash change subscribe function

**setHash** (optional): `replaceState` or a custom function that describes how hash gets updated on the side of the browser. Defaults to pushing a new entry to the history via `window.location.hash = searchParams` ([jotai-location#4](https://github.com/jotaijs/jotai-location/pull/4))

### Examples

```jsx
import { useAtom } from 'jotai'
import { atomWithHash } from 'jotai-location'

const countAtom = atomWithHash('count', 1)

const Counter = () => {
  const [count, setCount] = useAtom(countAtom)
  return (
    <div>
      <div>count: {count}</div>
      <button onClick={() => setCount((c) => c + 1)}>+1</button>
    </div>
  )
}
```

### Stackblitz

<Stackblitz id="vitejs-vite-zngpjt" file="src%2FApp.tsx" />

### Deleting Item

Please refer [atomWithStorage](../utilities/storage.mdx)
for the usage about deleting items.


================================================
FILE: docs/extensions/optics.mdx
================================================
---
title: Optics
description: This doc describes Optics-ts extension.
nav: 4.09
keywords: optics
---

### Install

You have to install `optics-ts` and `jotai-optics` to use this feature.

```
npm install optics-ts jotai-optics
```

## focusAtom

`focusAtom` creates a new atom, based on the focus that you pass to it. This creates a derived atom that will focus on the specified part of the atom,
and when the derived atom is updated, the derivee is notified of the update, and the equivalent update is done on the derivee.

See this:

```js
const baseAtom = atom({ a: 5 }) // PrimitiveAtom<{a: number}>
const derivedAtom = focusAtom(baseAtom, (optic) => optic.prop('a')) // PrimitiveAtom<number>
```

So basically, we started with a `PrimitiveAtom<{a: number}>`, which has a getter and a setter, and then used `focusAtom` to zoom in on the `a`-property of
the `baseAtom`, and got a `PrimitiveAtom<number>`. What is noteworthy here is that this `derivedAtom` is not only a getter, it is also a setter. If `derivedAtom` is updated, then equivalent update is done on the `baseAtom`.

The example below is simple, but it's a starting point. `focusAtom` supports many kinds of optics, including `Lens`, `Prism`, `Isomorphism`.

To see more advanced optics, please see the example at: https://github.com/akheron/optics-ts

### Example

```jsx
import { atom } from 'jotai'
import { focusAtom } from 'jotai-optics'

const objectAtom = atom({ a: 5, b: 10 })
const aAtom = focusAtom(objectAtom, (optic) => optic.prop('a'))
const bAtom = focusAtom(objectAtom, (optic) => optic.prop('b'))

const Controls = () => {
  const [a, setA] = useAtom(aAtom)
  const [b, setB] = useAtom(bAtom)
  return (
    <div>
      <span>Value of a: {a}</span>
      <span>Value of b: {b}</span>
      <button onClick={() => setA((oldA) => oldA + 1)}>Increment a</button>
      <button onClick={() => setB((oldB) => oldB + 1)}>Increment b</button>
    </div>
  )
}
```

#### Stackblitz

<Stackblitz id="vitejs-vite-jjunki" file="src%2FApp.tsx" />


================================================
FILE: docs/extensions/query.mdx
================================================
---
title: Query
description: This doc describes TanStack Query extension.
nav: 4.02
keywords: tanstack,query
---

[TanStack Query](https://tanstack.com/query/) provides a set of functions for managing async state (typically external data).

From the [Overview docs](https://tanstack.com/query/v5/docs/framework/react/overview):

> React Query is often described as the missing data-fetching library for React, but in more technical terms, it makes **fetching, caching, synchronizing and updating server state** in your React applications a breeze.

[jotai-tanstack-query](https://github.com/jotai-labs/jotai-tanstack-query) is a Jotai extension library for TanStack Query. It provides a wonderful interface with all of the TanStack Query features, providing you the ability to use those features in combination with your existing Jotai state.

### Support

jotai-tanstack-query currently supports TanStack Query v5.

### Install

In addition to `jotai`, you have to install `jotai-tanstack-query` and `@tanstack/query-core` to use the extension.

```bash
npm install jotai-tanstack-query @tanstack/query-core
```

### Incremental Adoption

You can incrementally adopt `jotai-tanstack-query` in your app. It's not an all or nothing solution. You just have to ensure you are using the same QueryClient instance. [QueryClient Setup](#referencing-the-same-instance-of-query-client-in-your-project).

```jsx
// existing useQueryHook
const { data, isPending, isError } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})

// jotai-tanstack-query
const todosAtom = atomWithQuery(() => ({
  queryKey: ['todos'],
}))

const [{ data, isPending, isError }] = useAtom(todosAtom)
```

### Exported functions

- `atomWithQuery` for [useQuery](https://tanstack.com/query/v5/docs/react/reference/useQuery)
- `atomWithInfiniteQuery` for [useInfiniteQuery](https://tanstack.com/query/v5/docs/react/reference/useInfiniteQuery)
- `atomWithMutation` for [useMutation](https://tanstack.com/query/v5/docs/react/reference/useMutation)
- `atomWithSuspenseQuery` for [useSuspenseQuery](https://tanstack.com/query/v5/docs/react/reference/useSuspenseQuery)
- `atomWithSuspenseInfiniteQuery` for [useSuspenseInfiniteQuery](https://tanstack.com/query/v5/docs/react/reference/useSuspenseInfiniteQuery)
- `atomWithMutationState` for [useMutationState](https://tanstack.com/query/v5/docs/react/reference/useMutationState)

All functions follow the same signature.

```ts
const dataAtom = atomWithSomething(getOptions, getQueryClient)
```

The first `getOptions` parameter is a function that returns an input to the observer.
The second optional `getQueryClient` parameter is a function that return [QueryClient](https://tanstack.com/query/v5/docs/reference/QueryClient).

### atomWithQuery usage

`atomWithQuery` creates a new atom that implements a standard [`Query`](https://tanstack.com/query/v5/docs/react/guides/queries) from TanStack Query.

```jsx
import { atom, useAtom } from 'jotai'
import { atomWithQuery } from 'jotai-tanstack-query'

const idAtom = atom(1)
const userAtom = atomWithQuery((get) => ({
  queryKey: ['users', get(idAtom)],
  queryFn: async ({ queryKey: [, id] }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
    return res.json()
  },
}))

const UserData = () => {
  const [{ data, isPending, isError }] = useAtom(userAtom)

  if (isPending) return <div>Loading...</div>
  if (isError) return <div>Error</div>

  return <div>{JSON.stringify(data)}</div>
}
```

### atomWithInfiniteQuery usage

`atomWithInfiniteQuery` is very similar to `atomWithQuery`, however it is for an `InfiniteQuery`, which is used for data that is meant to be paginated. You can [read more about Infinite Queries here](https://tanstack.com/query/v5/docs/framework/react/guides/infinite-queries).

> Rendering lists that can additively "load more" data onto an existing set of data or "infinite scroll" is also a very common UI pattern. React Query supports a useful version of useQuery called useInfiniteQuery for querying these types of lists.

A notable difference between a standard query atom is the additional option `getNextPageParam` and `getPreviousPageParam`, which is what you'll use to instruct the query on how to fetch any additional pages.

```jsx
import { atom, useAtom } from 'jotai'
import { atomWithInfiniteQuery } from 'jotai-tanstack-query'

const postsAtom = atomWithInfiniteQuery(() => ({
  queryKey: ['posts'],
  queryFn: async ({ pageParam }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${pageParam}`)
    return res.json()
  },
  getNextPageParam: (lastPage, allPages, lastPageParam) => lastPageParam + 1,
  initialPageParam: 1,
}))

const Posts = () => {
  const [{ data, fetchNextPage, isPending, isError, isFetching }] =
    useAtom(postsAtom)

  if (isPending) return <div>Loading...</div>
  if (isError) return <div>Error</div>

  return (
    <>
      {data.pages.map((page, index) => (
        <div key={index}>
          {page.map((post: any) => (
            <div key={post.id}>{post.title}</div>
          ))}
        </div>
      ))}
      <button onClick={() => fetchNextPage()}>Next</button>
    </>
  )
}
```

### atomWithMutation usage

`atomWithMutation` creates a new atom that implements a standard [`Mutation`](https://tanstack.com/query/v5/docs/framework/react/guides/mutations) from TanStack Query.

> Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects.

```tsx
const postAtom = atomWithMutation(() => ({
  mutationKey: ['posts'],
  mutationFn: async ({ title }: { title: string }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts`, {
      method: 'POST',
      body: JSON.stringify({
        title,
        body: 'body',
        userId: 1,
      }),
      headers: {
        'Content-type': 'application/json; charset=UTF-8',
      },
    })
    const data = await res.json()
    return data
  },
}))

const Posts = () => {
  const [{ mutate, status }] = useAtom(postAtom)
  return (
    <div>
      <button onClick={() => mutate({ title: 'foo' })}>Click me</button>
      <pre>{JSON.stringify(status, null, 2)}</pre>
    </div>
  )
}
```

### atomWithMutationState usage

`atomWithMutationState` creates a new atom that gives you access to all mutations in the [`MutationCache`](https://tanstack.com/query/v5/docs/react/reference/useMutationState).

```jsx
const mutationStateAtom = atomWithMutationState((get) => ({
  filters: {
    mutationKey: ['posts'],
  },
}))
```

### Suspense

jotai-tanstack-query can also be used with React's Suspense.

### atomWithSuspenseQuery usage

```jsx
import { atom, useAtom } from 'jotai'
import { atomWithSuspenseQuery } from 'jotai-tanstack-query'

const idAtom = atom(1)
const userAtom = atomWithSuspenseQuery((get) => ({
  queryKey: ['users', get(idAtom)],
  queryFn: async ({ queryKey: [, id] }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
    return res.json()
  },
}))

const UserData = () => {
  const [{ data }] = useAtom(userAtom)

  return <div>{JSON.stringify(data)}</div>
}
```

### atomWithSuspenseInfiniteQuery usage

```jsx
import { atom, useAtom } from 'jotai'
import { atomWithSuspenseInfiniteQuery } from 'jotai-tanstack-query'

const postsAtom = atomWithSuspenseInfiniteQuery(() => ({
  queryKey: ['posts'],
  queryFn: async ({ pageParam }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${pageParam}`)
    return res.json()
  },
  getNextPageParam: (lastPage, allPages, lastPageParam) => lastPageParam + 1,
  initialPageParam: 1,
}))

const Posts = () => {
  const [{ data, fetchNextPage, isPending, isError, isFetching }] =
    useAtom(postsAtom)

  return (
    <>
      {data.pages.map((page, index) => (
        <div key={index}>
          {page.map((post: any) => (
            <div key={post.id}>{post.title}</div>
          ))}
        </div>
      ))}
      <button onClick={() => fetchNextPage()}>Next</button>
    </>
  )
}
```

### Referencing the same instance of Query Client in your project

Perhaps you have some custom hooks in your project that utilises the `useQueryClient()` hook to obtain the `QueryClient` object and call its methods.

To ensure that you reference the same `QueryClient` object, be sure to wrap the root of your project in a `<Provider>` and initialise `queryClientAtom` with the same `queryClient` value you provided to `QueryClientProvider`.

Without this step, `useQueryAtom` will reference a separate `QueryClient` from any hooks that utilise the `useQueryClient()` hook to get the queryClient.

Alternatively, you can specify your `queryClient` with `getQueryClient` parameter.

#### Example

In the example below, we have a mutation hook, `useTodoMutation` and a query `todosAtom`.

We included an initialisation step in our root `<App>` node.

Although they reference methods same query key (`'todos'`), the `onSuccess` invalidation in `useTodoMutation` will not trigger **if the `Provider` initialisation step was not done.**

This will result in `todosAtom` showing stale data as it was not prompted to refetch.

⚠️ Note: When using **Typescript**, it is recommended to use a Map when passing the queryClient value to useHydrateAtoms. You can find a working example in the [Initializing State on Render docs](https://jotai.org/docs/guides/initialize-atom-on-render#using-typescript)

```jsx
import { Provider } from 'jotai/react'
import { useHydrateAtoms } from 'jotai/react/utils'
import {
  useMutation,
  useQueryClient,
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'
import { atomWithQuery, queryClientAtom } from 'jotai-tanstack-query'

const queryClient = new QueryClient()

const HydrateAtoms = ({ children }) => {
  useHydrateAtoms([[queryClientAtom, queryClient]])
  return children
}

export const App = () => {
  return (
    <QueryClientProvider client={queryClient}>
      <Provider>
        {/*
   This Provider initialisation step is needed so that we reference the same
   queryClient in both atomWithQuery and other parts of the app. Without this,
   our useQueryClient() hook will return a different QueryClient object
	*/}
        <HydrateAtoms>
          <App />
        </HydrateAtoms>
      </Provider>
    </QueryClientProvider>
  )
}

export const todosAtom = atomWithQuery((get) => {
  return {
    queryKey: ['todos'],
    queryFn: () => fetch('/todos'),
  }
})

export const useTodoMutation = () => {
  const queryClient = useQueryClient()

  return useMutation(
    async (body: todo) => {
      await fetch('/todo', { Method: 'POST', Body: body })
    },
    {
      onSuccess: () => {
        void queryClient.invalidateQueries(['todos'])
      },
      onError,
    }
  )
}
```

### SSR support

All atoms can be used within the context of a server side rendered app, such as a next.js app or Gatsby app. You can [use both options](https://tanstack.com/query/v5/docs/framework/react/guides/ssr) that React Query supports for use within SSR apps, [hydration](https://tanstack.com/query/v5/docs/react/guides/ssr#using-the-hydration-apis) or [`initialData`](https://tanstack.com/query/v5/docs/react/guides/ssr#get-started-fast-with-initialdata).

### Error handling

Fetch error will be thrown and can be caught with ErrorBoundary.
Refetching may recover from a temporary error.

See [a working example](https://codesandbox.io/s/4gfp6z) to learn more.

### Devtools

In order to use the Devtools, you need to install it additionally.

```bash
npm install @tanstack/react-query-devtools
```

All you have to do is put the `<ReactQueryDevtools />` within `<QueryClientProvider />`.

```tsx
import {
  QueryClientProvider,
  QueryClient,
  QueryCache,
} from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { queryClientAtom } from 'jotai-tanstack-query'

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: Infinity,
    },
  },
})

const HydrateAtoms = ({ children }) => {
  useHydrateAtoms([[queryClientAtom, queryClient]])
  return children
}

export const App = () => {
  return (
    <QueryClientProvider client={queryClient}>
      <Provider>
        <HydrateAtoms>
          <App />
        </HydrateAtoms>
      </Provider>
      <ReactQueryDevtools />
    </QueryClientProvider>
  )
}
```

## Migrate to v0.8.0

### Change in atom signature

All atom signatures have changed to be more consistent with TanStack Query.
v0.8.0 returns only a single atom, instead of a tuple of atoms, and hence the name change from `atomsWithSomething` to`atomWithSomething`.

```diff

- const [dataAtom, statusAtom] = atomsWithSomething(getOptions, getQueryClient)
+ const dataAtom = atomWithSomething(getOptions, getQueryClient)

```

### Simplified Return Structure

In the previous version of `jotai-tanstack-query`, the query atoms `atomsWithQuery` and `atomsWithInfiniteQuery` returned a tuple of atoms: `[dataAtom, statusAtom]`. This design separated the data and its status into two different atoms.

#### atomWithQuery and atomWithInfiniteQuery

- `dataAtom` was used to access the actual data (`TData`).
- `statusAtom` provided the status object (`QueryObserverResult<TData, TError>`), which included additional attributes like `isPending`, `isError`, etc.

In v0.8.0, they have been replaced by `atomWithQuery` and `atomWithInfiniteQuery` to return only a single `dataAtom`. This `dataAtom` now directly provides the `QueryObserverResult<TData, TError>`, aligning it closely with the behavior of Tanstack Query's bindings.

To migrate to the new version, replace the separate `dataAtom` and `statusAtom` usage with the unified `dataAtom` that now contains both data and status information.

```diff
- const [dataAtom, statusAtom] = atomsWithQuery(/* ... */);
- const [data] = useAtom(dataAtom);
- const [status] = useAtom(statusAtom);

+ const dataAtom = atomWithQuery(/* ... */);
+ const [{ data, isPending, isError }] = useAtom(dataAtom);
```

#### atomWithMutation

Similar to `atomsWithQuery` and `atomsWithInfiniteQuery`, `atomWithMutation` also returns a single atom instead of a tuple of atoms. The return type of the atom value is `MutationObserverResult<TData, TError, TVariables, TContext>`.

```diff

- const [, postAtom] = atomsWithMutation(/* ... */);
- const [post, mutate] = useAtom(postAtom); // Accessing mutation status from post; and mutate() to execute the mutation

+ const postAtom = atomWithMutation(/* ... */);
+ const [{ data, error, mutate }] = useAtom(postAtom); // Accessing mutation result and mutate method from the same atom

```

### Examples

#### Basic demo

<Stackblitz id="vitejs-vite-pr9eaf" file="src%2FApp.tsx" />

#### Devtools demo

<Stackblitz id="vitejs-vite-btdqkh" file="src%2FApp.tsx" />

#### Hackernews

<Stackblitz id="vitejs-vite-wqsyj8" file="src%2FApp.tsx" />


================================================
FILE: docs/extensions/redux.mdx
================================================
---
title: Redux
description: This doc describes Redux extension.
nav: 4.98
keywords: redux
published: false
---

Jotai's state resides in React, but sometimes it would be nice
to interact with the world outside React.

Redux provides a store interface that can be used to store some values
and sync with atoms in Jotai.

### Install

You have to install `redux` and `jotai-redux` to use this feature.

```
npm install redux jotai-redux
```

## atomWithStore

`atomWithStore` creates a new atom with redux store.
It's two-way binding and you can change the value from both ends.

```jsx
import { useAtom } from 'jotai'
import { atomWithStore } from 'jotai-redux'
import { createStore } from 'redux'

const initialState = { count: 0 }
const reducer = (state = initialState, action: { type: 'INC' }) => {
  if (action.type === 'INC') {
    return { ...state, count: state.count + 1 }
  }
  return state
}
const store = createStore(reducer)
const storeAtom = atomWithStore(store)

const Counter = () => {
  const [state, dispatch] = useAtom(storeAtom)

  return (
    <>
      count: {state.count}
      <button onClick={() => dispatch({ type: 'INC' })}>button</button>
    </>
  )
}
```

### Examples

<Stackblitz id="vitejs-vite-qqsnwc" file="src%2FApp.tsx" />


================================================
FILE: docs/extensions/relay.mdx
================================================
---
title: Relay
description: This doc describes Relay extension.
nav: 4.98
keywords: relay
published: false
---

You can use Jotai with [Relay](https://relay.dev).

### Install

You have to install `jotai-relay` and `relay-runtime`.

```
npm install jotai-relay relay-runtime
```

### Usage

See [Relay Docs](https://relay.dev/docs/) to
learn about basics and how to use compiler in advance.

### atomWithQuery

`atomWithQuery` creates a new atom with [fetchQuery](https://relay.dev/docs/api-reference/fetch-query/).

```jsx
import React, { Suspense } from 'react'
import { Provider, useAtom } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'
import { environmentAtom, atomWithQuery } from 'jotai-relay'
import { Environment, Network, RecordSource, Store } from 'relay-runtime'
import graphql from 'babel-plugin-relay/macro'

const myEnvironment = new Environment({
  network: Network.create(async (params, variables) => {
    const response = await fetch('https://countries.trevorblades.com/', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        query: params.text,
        variables,
      }),
    })
    return response.json()
  }),
  store: new Store(new RecordSource()),
})

const countriesAtom = atomWithQuery(
  graphql`
    query AppCountriesQuery {
      countries {
        name
      }
    }
  `,
  () => ({}),
)

const Main = () => {
  const [data] = useAtom(countriesAtom)
  return (
    <ul>
      {data.countries.map(({ name }) => (
        <li key={name}>{name}</li>
      ))}
    </ul>
  )
}

const HydrateAtoms = ({ children }) => {
  useHydrateAtoms([[environmentAtom, myEnvironment]])
  return children
}

const App = () => {
  return (
    <Provider>
      <HydrateAtoms>
        <Suspense fallback="Loading...">
          <Main />
        </Suspense>
      </HydrateAtoms>
    </Provider>
  )
}
```

#### Examples

<Stackblitz id="vitejs-vite-divyhe" file="src%2FApp.tsx" />

### atomWithMutation

`atomWithMutation` creates a new atom with [commitMutation](https://relay.dev/docs/api-reference/commit-mutation/).

FIXME: add code example and codesandbox

### atomWithSubscription

`atomWithSubscription` creates a new atom with [requestSubscription](https://relay.dev/docs/api-reference/request-subscription/).

FIXME: add code example and codesandbox


================================================
FILE: docs/extensions/scope.mdx
================================================
---
title: Scope
description: This doc describes scope extension.
nav: 4.08
keywords: scope
---

There are a few libraries to extend Jotai's usage in React.

## `jotai-scope`

While Jotai's Provider allows to scope Jotai's store under a subtree,
we can't use the store above the tree within the subtree.

A workaround is to use `store` option in useAtom and other hooks.

Instead of specifying the `store` option,
`<ScopeProvider>` lets you reuse the _same_ atoms in different parts
of the React tree **without sharing state** while still being able to
read other atoms from the parent store.

### Install

```
npm install jotai-scope
```

### Counter Example

```tsx
import { atom, useAtom } from 'jotai'
import { ScopeProvider } from 'jotai-scope'

const countAtom = atom(0)

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  const [anotherCount, setAnotherCount] = useAtom(anotherCountAtom)
  return (
    <>
      <div>
        <span>count: {count}</span>
        <button type="button" onClick={() => setCount((v) => v + 1)}>
          increment
        </button>
      </div>
      <div>
        <span>another count: {anotherCount}</span>
        <button type="button" onClick={() => setAnotherCount((v) => v + 1)}>
          increment
        </button>
      </div>
    </>
  )
}

function App() {
  return (
    <div>
      <Counter />
      <ScopeProvider atoms={[countAtom]}>
        <Counter />
      </ScopeProvider>
    </div>
  )
}
```

<Stackblitz id="vitejs-vite-ctcuhj" file="src%2FApp.tsx" />

## `createIsolation`

Both Jotai's Provider and `jotai-scope`'s scoped provider
are still using global contexts.

If you are developing a library that depends on Jotai and
the library user may use Jotai separately in their apps,
they can share the same context. This can be troublesome
because they point to unexpected Jotai stores.

To avoid conflicting the contexts,
a utility function called `createIsolation` is exported from `jotai-scope`.

```tsx
import { createIsolation } from 'jotai-scope'

const { Provider, useStore, useAtom, useAtomValue, useSetAtom } =
  createIsolation()

function Library() {
  return (
    <Provider>
      <LibraryComponent />
    </Provider>
  )
}
```

## `bunshi` (formerly `jotai-molecules`)

Jotai atoms provide a basic solution to optimize re-renders.
Atoms defined globally can depend on other atoms,
but they can't depend on props and state within a component tree.
It's possible to define atoms within a component tree,
but then you would need to pass those atoms in some ways
(for example, [atoms-in-atom](../guides/atoms-in-atom.mdx).)

[bunshi](https://github.com/saasquatch/bunshi) is
a third-party library to help such use cases.

See [Motivation](https://github.com/saasquatch/bunshi/tree/v1.1.1#motivation) for more details.

### Install

```
npm install bunshi
```

### Counter Example

```jsx
import { atom, useAtom } from 'jotai'
import { molecule, useMolecule, createScope, ScopeProvider } from 'bunshi/react'

const InitialCountScope = createScope({ initialCount: 0 })
const countMolecule = molecule((getMol, getScope) => {
  const { initialCount } = getScope(InitialCountScope)
  return atom(initialCount)
})

function Counter() {
  const countAtom = useMolecule(countMolecule)
  const [count, setCount] = useAtom(countAtom)
  return (
    <div>
      {count} <button onClick={() => setCount((v) => v + 1)}>+1</button>
    </div>
  )
}

function App() {
  return (
    <div>
      <h1>With initial value 1</h1>
      <ScopeProvider scope={InitialCountScope} value={{ initialCount: 1 }}>
        <Counter />
        <Counter />
      </ScopeProvider>
      <h1>With initial value 2</h1>
      <ScopeProvider scope={InitialCountScope} value={{ initialCount: 2 }}>
        <Counter />
        <Counter />
      </ScopeProvider>
      <h1>Default</h1>
      <Counter />
      <Counter />
    </div>
  )
}
```

<Stackblitz id="vitejs-vite-8akpt6" file="src%2FApp.tsx" />


================================================
FILE: docs/extensions/trpc.mdx
================================================
---
title: tRPC
description: This doc describes tRPC extension.
nav: 4.01
keywords: rpc,trpc,typescript,t3
---

You can use Jotai with [tRPC](https://trpc.io).

### Install

You have to install `jotai-trpc`, `@trpc/client` and `@trpc/server` to use the extension.

```
npm install jotai-trpc @trpc/client @trpc/server
```

### Usage

```ts
import { createTRPCJotai } from 'jotai-trpc'

const trpc = createTRPCJotai<MyRouter>({
  links: [
    httpLink({
      url: myUrl,
    }),
  ],
})

const idAtom = atom('foo')
const queryAtom = trpc.bar.baz.atomWithQuery((get) => get(idAtom))
```

### atomWithQuery

`...atomWithQuery` creates a new atom with "query". It internally uses [Vanilla Client](https://trpc.io/docs/vanilla)'s `...query` procedure.

```tsx
import { atom, useAtom } from 'jotai'
import { httpLink } from '@trpc/client'
import { createTRPCJotai } from 'jotai-trpc'
import { trpcPokemonUrl } from 'trpc-pokemon'
import type { PokemonRouter } from 'trpc-pokemon'

const trpc = createTRPCJotai<PokemonRouter>({
  links: [
    httpLink({
      url: trpcPokemonUrl,
    }),
  ],
})

const NAMES = [
  'bulbasaur',
  'ivysaur',
  'venusaur',
  'charmander',
  'charmeleon',
  'charizard',
  'squirtle',
  'wartortle',
  'blastoise',
]

const nameAtom = atom(NAMES[0])

const pokemonAtom = trpc.pokemon.byId.atomWithQuery((get) => get(nameAtom))

const Pokemon = () => {
  const [data, refresh] = useAtom(pokemonAtom)
  return (
    <div>
      <div>ID: {data.id}</div>
      <div>Height: {data.height}</div>
      <div>Weight: {data.weight}</div>
      <button onClick={refresh}>Refresh</button>
    </div>
  )
}
```

#### Examples

<Stackblitz id="vitejs-vite-8kgfpj" file="src%2FApp.tsx" />

### atomWithMutation

`...atomWithMutation` creates a new atom with "mutate". It internally uses [Vanilla Client](https://trpc.io/docs/vanilla)'s `...mutate` procedure.

FIXME: add code example and codesandbox

### atomWithSubscription

`...atomWithSubscription` creates a new atom with "subscribe". It internally uses [Vanilla Client](https://trpc.io/docs/vanilla)'s `...subscribe` procedure.

FIXME: add code example and codesandbox


================================================
FILE: docs/extensions/urql.mdx
================================================
---
title: URQL
description: This doc describes URQL extension.
nav: 4.03
keywords: urql
---

[urql](https://formidable.com/open-source/urql/) offers a toolkit for GraphQL querying, caching, and state management.

From the [Overview docs](https://formidable.com/open-source/urql/docs/):

> urql is a highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow. It's built to be both easy to use for newcomers to GraphQL, and extensible, to grow to support dynamic single-app applications and highly customized GraphQL infrastructure. In short, urql prioritizes usability and adaptability.

[jotai-urql](https://github.com/jotaijs/jotai-urql) is a Jotai extension library for URQL. It offers a cohesive interface that incorporates all of URQL's GraphQL features, allowing you to leverage these functionalities alongside your existing Jotai state.

### Install

You have to install `jotai-urql`, `@urql/core` and `wonka` to use the extension.

```
npm install jotai-urql @urql/core wonka
```

### Exported functions

- `atomWithQuery` for [client.query](https://formidable.com/open-source/urql/docs/api/core/#clientquery)
- `atomWithMutation` for [client.mutation](https://formidable.com/open-source/urql/docs/api/core/#clientmutation)
- `atomWithSubscription` for [client.subscription](https://formidable.com/open-source/urql/docs/api/core/#clientsubscription)

### Basic usage

#### Query:

```tsx
import { useAtom } from 'jotai'

const countQueryAtom = atomWithQuery<{ count: number }>({
  query: 'query Count { count }',
  getClient: () => client, // This option is optional if `useRehydrateAtom([[clientAtom, client]])` is used globally
})

const Counter = () => {
  // Will suspend until first operation result is resolved. Either with error, partial data, data
  const [operationResult, reexecute] = useAtom(countQueryAtom)

  if (operationResult.error) {
    // This shall be handled in the parent ErrorBoundary above
    throw operationResult.error
  }

  // You have to use optional chaining here, as data may be undefined at this point (only in case of error)
  return <>{operationResult.data?.count}</>
}
```

#### Mutation:

```tsx
import { useAtom } from 'jotai'

const incrementMutationAtom = atomWithMutation<{ increment: number }>({
  query: 'mutation Increment { increment }',
})

const Counter = () => {
  const [operationResult, executeMutation] = useAtom(incrementMutationAtom)
  return (
    <div>
      <button
        onClick={() =>
          executeMutation().then((it) => console.log(it.data?.increment))
        }
      >
        Increment
      </button>
      <div>{operationResult.data?.increment}</div>
    </div>
  )
}
```

### Simplified type of options passed to functions

```tsx
type AtomWithQueryOptions<
  Data = unknown,
  Variables extends AnyVariables = AnyVariables,
> = {
  // Supports string query, typed-document-node, document node etc.
  query: DocumentInput<Data, Variables>
  // Will be enforced dynamically based on generic/typed-document-node types.
  getVariables?: (get: Getter) => Variables
  getContext?: (get: Getter) => Partial<OperationContext>
  getPause?: (get: Getter) => boolean
  getClient?: (get: Getter) => Client
}

type AtomWithMutationOptions<
  Data = unknown,
  Variables extends AnyVariables = AnyVariables,
> = {
  query: DocumentInput<Data, Variables>
  getClient?: (get: Getter) => Client
}

// Subscription type is the same as AtomWithQueryOptions
```

### Disable suspense

Usage of `import { loadable } from "jotai/utils"` is preferred instead as proven more stable. However is you still want that
here is how you do it:

```tsx
import { suspenseAtom } from 'jotai-urql'

export const App = () => {
  // We disable suspense for the entire app
  useHydrateAtoms([[suspenseAtom, false]])
  return <Counter />
}
```

### Useful helper hook

Here is the helper hook, to cover one rare corner case, and make use of these bindings similar to `@tanstack/react-query`
default behavior where errors are treated as errors (in case of Promise reject) and are handled mostly in the nearby
ErrorBoundaries. Only valid for suspended version.

#### useQueryAtomData

Neatly returns `data` after the resolution + handles all the error throwing/reexecute cases/corner cases.
Note that Type is overridden so `data` it never `undefined` nor `null` (unless that's expected return type of the query itself)

```tsx
import type { AnyVariables, OperationResult } from '@urql/core'
import { useAtom } from 'jotai'
import type { AtomWithQuery } from 'jotai-urql'

export const useQueryAtomData = <
  Data = unknown,
  Variables extends AnyVariables = AnyVariables,
>(
  queryAtom: AtomWithQuery<Data, Variables>,
) => {
  const [opResult, dispatch] = useAtom(queryAtom)

  if (opResult.error && opResult.stale) {
    use(
      // Here we suspend the tree. This will only be triggered in the scenario
      // when you use `network-only` for refetch in Error Boundary retry logic, in that case tree doesn't suspend
      // causing possible "throwed - retry in boundary - throwed - retry in boundary" cycle.
      // (in case of Jotai URQL bindings only).
      // eslint-disable-next-line promise/avoid-new
      new Promise((resolve) => {
        setTimeout(resolve, 10000) // This timeout time is going to cause suspense of this component up until
        // new operation result will come. After 10 second it will simply try to render component itself and suspend again
        // in an endless loop
      }),
    )
  }

  if (opResult.error) {
    throw opResult.error
  }

  if (!opResult.data) {
    throw Error(
      'Query data is undefined. Probably you paused the query? In that case use `useQueryAtom` instead.',
    )
  }
  return [opResult.data, dispatch, opResult] as [
    Exclude<typeof opResult.data, undefined>,
    typeof dispatch,
    typeof opResult,
  ]
}

// Suspense tree while promise is resolving (not going to be needed in next versions of React)
function use(promise: Promise<any> | any) {
  if (promise.status === 'fulfilled') {
    return promise.value
  }
  if (promise.status === 'rejected') {
    throw promise.reason
  } else if (promise.status === 'pending') {
    throw promise
  } else {
    promise.status = 'pending'
    // eslint-disable-next-line promise/catch-or-return
    ;(promise as Promise<any>).then(
      (result: any) => {
        promise.status = 'fulfilled'
        promise.value = result
      },
      (reason: any) => {
        promise.status = 'rejected'
        promise.reason = reason
      },
    )
    throw promise
  }
}
```

#### Basic demo

<Stackblitz id="vitejs-vite-1nhtrj" file="src%2FApp.tsx" />

### Referencing the same instance of the client for both atoms and urql provider

To ensure that you reference the same urqlClient object, be sure to wrap the root of your project in a `<Provider>` and initialise clientAtom with the same urqlClient value you provided to UrqlProvider.

Without this step, you may end up specifying client each time when you use `atomWithQuery`. Now you can just ignore the optional `getClient` parameter, and it will use the client from the context.

```jsx
import { Suspense } from 'react'
import { Provider } from 'jotai/react'
import { useHydrateAtoms } from 'jotai/react/utils'
import { clientAtom } from 'jotai-urql'

import {
  createClient,
  cacheExchange,
  fetchExchange,
  Provider as UrqlProvider,
} from 'urql'

const urqlClient = createClient({
  url: 'https://countries.trevorblades.com/',
  exchanges: [cacheExchange, fetchExchange],
  fetchOptions: () => {
    return { headers: {} }
  },
})

const HydrateAtoms = ({ children }) => {
  useHydrateAtoms([[clientAtom, urqlClient]])
  return children
}

export default function MyApp({ Component, pageProps }) {
  return (
    <UrqlProvider value={urqlClient}>
      <Provider>
        <HydrateAtoms>
          <Suspense fallback="Loading...">
            <Component {...pageProps} />
          </Suspense>
        </HydrateAtoms>
      </Provider>
    </UrqlProvider>
  )
}
```


================================================
FILE: docs/extensions/valtio.mdx
================================================
---
title: Valtio
description: This doc describes Valtio extension.
nav: 4.98
keywords: valtio,proxy
published: false
---

Jotai's state resides in React, but sometimes it would be nice
to interact with the world outside React.

Valtio provides a proxy interface that can be used to store some values
and sync with atoms in Jotai.

This only uses the vanilla api of valtio.

### Install

You have to install `valtio` and `jotai-valtio` to use this feature.

```
npm install valtio jotai-valtio
```

## atomWithProxy

`atomWithProxy` creates a new atom with valtio proxy.
It's two-way binding and you can change the value from both ends.

```jsx
import { useAtom } from 'jotai'
import { atomWithProxy } from 'jotai-valtio'
import { proxy } from 'valtio/vanilla'

const proxyState = proxy({ count: 0 })
const stateAtom = atomWithProxy(proxyState)
const Counter = () => {
  const [state, setState] = useAtom(stateAtom)

  return (
    <>
      count: {state.count}
      <button
        onClick={() => setState((prev) => ({ ...prev, count: prev.count + 1 }))}
      >
        inc atom
      </button>
      <button
        onClick={() => {
          ++proxyState.count
        }}
      >
        inc proxy
      </button>
    </>
  )
}
```

### Parameters

```
atomWithProxy(proxyObject, options?)
```

**proxyObject** (required): the Valtio proxy object you want to derive the atom from

**options.sync** (optional): makes the atom update synchronously instead of waiting for batched updates, similar to [`valtio/useSnapshot`](https://github.com/pmndrs/valtio#update-synchronously). This will result in more renders, but have more guarantees that it syncs with other Jotai atoms.

```
atomWithProxy(proxyObject, { sync: true })
```

### Examples

<Stackblitz id="vitejs-vite-wmsazx" file="src%2FApp.tsx" />

## mutableAtom

`mutableAtom` wraps a value in a self-aware Valtio proxy. You can make changes to it in the same way you would to a normal js-object.

Count value is stored under the `value` property.

```jsx
const countProxyAtom = mutableAtom(0)

function IncrementButton() {
  const countProxy = useAtomValue(countProxyAtom)
  return <button onClick={() => ++countProxy.value}>+</button>
}
```

### Parameters

```js
mutableAtom(value, options?)
```

**value** (required): the value to proxy.

**options.proxyFn** (optional): allows customization with `proxyFn` for custom proxy functions. Can be `proxy` (default) or a custom function.

### Examples

<Stackblitz id="vitejs-vite-wmsazx" file="src%2FApp.tsx" />

### Caution on Mutating Proxies

Be careful to not mutate the proxy directly in the atom's read function or during render. Doing so could cause an infinite render loop.

```ts
const countProxyAtom = mutableAtom(0)

atom(
  (get) => {
    const countProxy = get(countProxyAtom)
    ++countProxy.value // This will cause an infinite loop
  },
  (get, set) => {
    const countProxy = get(countProxyAtom)
    ++countProxy.value // This is fine
  },
)
```


================================================
FILE: docs/extensions/xstate.mdx
================================================
---
title: XState
description: This doc describes XState extension.
nav: 4.05
keywords: xstate,machine,atomwithmachine
---

Jotai's state management is primitive and flexible,
but that sometimes means too free.
XState is a sophisticated library to provide
a better and safer abstraction for state management.

### Install

You have to install `xstate` and `jotai-xstate` to use this feature.

```
npm install xstate jotai-xstate
```

## atomWithMachine

`atomWithMachine` creates a new atom with XState machine.
It receives a function `getMachine` to create a new machine.
`getMachine` is invoked at the first use with `get` argument,
with which you can read other atom values.

```tsx
import { useAtom } from 'jotai'
import { atomWithMachine } from 'jotai-xstate'
import { assign, createMachine } from 'xstate'

const createEditableMachine = (value: string) =>
  createMachine<{ value: string }>({
    id: 'editable',
    initial: 'reading',
    context: {
      value,
    },
    states: {
      reading: {
        on: {
          dblclick: 'editing',
        },
      },
      editing: {
        on: {
          cancel: 'reading',
          commit: {
            target: 'reading',
            actions: assign({
              value: (_, { value }) => value,
            }),
          },
        },
      },
    },
  })

const defaultTextAtom = atom('edit me')
const editableMachineAtom = atomWithMachine((get) =>
  // `get` is available only for initializing a machine
  createEditableMachine(get(defaultTextAtom)),
)

const Toggle = () => {
  const [state, send] = useAtom(editableMachineAtom)

  return (
    <div>
      {state.matches('reading') && (
        <strong onDoubleClick={send}>{state.context.value}</strong>
      )}
      {state.matches('editing') && (
        <input
          autoFocus
          defaultValue={state.context.value}
          onBlur={(e) => send({ type: 'commit', value: e.target.value })}
          onKeyDown={(e) => {
            if (e.key === 'Enter') {
              send({ type: 'commit', value: e.target.value })
            }
            if (e.key === 'Escape') {
              send('cancel')
            }
          }}
        />
      )}
      <br />
      <br />
      <div>
        Double-click to edit. Blur the input or press <code>enter</code> to
        commit. Press <code>esc</code> to cancel.
      </div>
    </div>
  )
}
```

### Restartable machine stored in a global Provider (provider-less mode)

When your machine reaches its final state it cannot receive any more events.
If your atomWithMachine is initialized in global store (aka provider-less mode),
to restart it you need to send a `RESTART` event to your machine like so:

```tsx
import { RESTART } from 'jotai-xstate'

const YourComponent = () => {
  const [current, send] = useAtom(yourMachineAtom)

  const isFinalState = current.matches('myFinalState')

  useEffect(() => {
    // restart globally initialized machine on component unmount
    return () => {
      if (isFinalState) send(RESTART)
    }
  }, [isFinalState])
}
```

### Examples

Check examples with atomWithMachine:

<Stackblitz id="vitejs-vite-oqfhy4" file="src%2FApp.tsx" />

Restartable machine:

<Stackblitz id="vitejs-vite-tqdtym" file="src%2FApp.tsx" />

### Tutorials

Check out a course about Jotai and XState.

[Complex State Management in React with Jotai and XState](https://egghead.io/courses/complex-state-management-in-react-with-jotai-and-xstate-3be0a740)

(Note: In the course, it uses `jotai/xstate` which is supersede by `jotai-xstate`.)


================================================
FILE: docs/extensions/zustand.mdx
================================================
---
title: Zustand
description: This doc describes Zustand extension.
nav: 4.98
keywords: zustand
published: false
---

Jotai's state resides in React, but sometimes it would be nice
to interact with the world outside React.

Zustand provides a store interface that can be used to hold some values
and sync with atoms in Jotai.

This only uses the vanilla api of zustand.

### Install

You have to install `zustand` and `jotai-zustand` to use this feature.

```
npm install zustand jotai-zustand
```

## atomWithStore

`atomWithStore` creates a new atom with zustand store.
It's two-way binding and you can change the value from both ends.

```jsx
import { useAtom } from 'jotai'
import { atomWithStore } from 'jotai-zustand'
import create from 'zustand/vanilla'

const store = create(() => ({ count: 0 }))
const stateAtom = atomWithStore(store)
const Counter = () => {
  const [state, setState] = useAtom(stateAtom)

  return (
    <>
      count: {state.count}
      <button
        onClick={() => setState((prev) => ({ ...prev, count: prev.count + 1 }))}
      >
        button
      </button>
    </>
  )
}
```

### Examples

<Stackblitz id="vitejs-vite-kfzyun" file="src%2FApp.tsx" />


================================================
FILE: docs/guides/async.mdx
================================================
---
title: Async
description: This doc describes about the behavior with async.
nav: 8.99
keywords: async
published: false
---

Using async atoms, you gain access to real-world data while still managing them directly from your atoms and with incredible ease.

We can separate them in two main categories:

- Async read atoms: async request is started instantly as soon as you try to get its value. You could relate to them as "smart getters".
- Async write atoms: async request is started at a specific moment. You could relate to them as "actions".

## Async read atom

The `read` function of an atom can return a promise.

```js
const countAtom = atom(1)
const asyncAtom = atom(async (get) => get(countAtom) * 2)
```

Jotai is inherently leveraging `Suspense` to handle asynchronous flows.

```jsx
const ComponentUsingAsyncAtoms = () => {
  const [num] = useAtom(asyncAtom)
  // here `num` is always `number` even though asyncAtom returns a Promise
}
const App = () => {
  return (
    <Suspense fallback={/* What to show while suspended */}>
      <ComponentUsingAsyncAtoms />
    </Suspense>
  )
}
```

Alternatively, you could avoid the inherent suspending that Jotai does for you, by wrapping your atoms with the [`loadable` API](../utilities/async.mdx).

If another atom uses an async atom, it will return a promise. So, we need to make the atom also async.

```js
const anotherAtom = atom(async (get) => (await get(asyncAtom)) / 2)
```

This also applies to an atom with write function.

```js
const asyncAtom = atom(async (get) => ...)
const writeAtom = atom(null, async (get, set, payload) => {
  await get(asyncAtom)
  // ...
})
```

## Async write atom

Async write atoms are another kind of async atom. When the `write` function of atom returns a promise.

```js
const countAtom = atom(1)
const asyncIncrementAtom = atom(null, async (get, set) => {
  // await something
  set(countAtom, get(countAtom) + 1)
})

const Component = () => {
  const [, increment] = useAtom(asyncIncrementAtom)
  const handleClick = () => {
    increment()
  }
  // ...
}
```

## Async sometimes

An interesting pattern that can be achieved with Jotai is switching from async to sync to trigger suspending when wanted.

```js
const request = async () =>
  fetch('https://jsonplaceholder.typicode.com/todos/1').then((res) =>
    res.json(),
  )
const baseAtom = atom(0)
const Component = () => {
  const [value, setValue] = useAtom(baseAtom)
  const handleClick = () => {
    setValue(request()) // Will suspend until request resolves
  }
  // ...
}
```

### Usage in TypeScript

In TypeScript `atom(0)` is inferred as `PrimitiveAtom<number>`. It cannot accept `Promise<number>` as a value so preceding code would not typecheck. To accommodate for that you need to type your atom explicitly and add `Promise<number>` as accepted value.

```ts
const baseAtom = atom<number | Promise<number>>(0) // Will accept sync and async values
```

## Async forever

Sometimes you may want to suspend until an unpredetermined moment (or never).

```js
const baseAtom = atom(new Promise(() => {})) // Will be suspend until set otherwise
```

## Suspense

Async support is first class in Jotai. It fully leverages React Suspense at its core.

> Technically, Suspense usage other than React.lazy is still unsupported / undocumented in React 17. If this is blocking, so you can still use the [`loadable` API](../utilities/async.mdx) to avoid suspending

To use async atoms, you need to wrap your component tree with `<Suspense>`.

> If you have a `<Provider>`, place **at least one** `<Suspense>` inside said `<Provider>`; otherwise, it may cause an endless loop while rendering the components.

```jsx
const App = () => (
  <Provider>
    <Suspense fallback="Loading...">
      <Layout />
    </Suspense>
  </Provider>
)
```

Having more `<Suspense>`s in the component tree is also possible and must be considered to profit from Jotai inherent handling at best.


================================================
FILE: docs/guides/atoms-in-atom.mdx
================================================
---
title: Atoms in atom
nav: 8.12
---

`atom()` creates an atom config, which is an object, but it doesn't hold a value.
Atom configs don't have string keys and we identify them with referential equality.
In other words, we can use an atom config like a key.

### Storing an atom config in useState

First things first, we can store an atom config in useState.

```jsx
const Component = ({ atom1, atom2 }) => {
  const [selectedAtom, setSelectedAtom] = useState(atom1)
  const [value] = useAtom(selectedAtom)
  return (
    <div>
      Selected value: {value}
      <button onClick={() => setSelectedAtom(atom1)}>Select an atom</button>
      <button onClick={() => setSelectedAtom(atom2)}>
        Select another atom
      </button>
    </div>
  )
}
```

Note that we can pass atoms configs as props.

It might not make any sense, but we could create an atom config on demand.

```jsx
const Component = () => {
  const [currentAtom, setCurrentAtom] = useState(() => atom(0))
  const [count, setCount] = useAtom(currentAtom)
  return (
    <div>
      Count: {count} <button onClick={() => setCount((c) => c + 1)}>+1</button>
      <button onClick={() => setCurrentAtom(atom(0))}>Create new</button>
    </div>
  )
}
```

### Storing an atom config in atom

Likewise, we can store an atom config as a value of another atom.

```jsx
const firstNameAtom = atom('Tanjiro')
const lastNameAtom = atom('Kamado')

const showingNameAtom = atom(firstNameAtom)

const Component = () => {
  const [nameAtom, setNameAtom] = useAtom(showingNameAtom)
  const [name] = useAtom(nameAtom)
  return (
    <div>
      Name: {name}
      <button onClick={() => setNameAtom(firstNameAtom)}>
        Show First Name
      </button>
      <button onClick={() => setNameAtom(lastNameAtom)}>Show Last Name</button>
    </div>
  )
}
```

It's possible to create a derived atom.

```js
const derivedNameAtom = atom((get) => {
  const nameAtom = get(showingNameAtom)
  return get(nameAtom)
})

// Or a shorter version
const derivedNameAtom = atom((get) => get(get(showingNameAtom)))
```

To avoid confusing what is in atoms, naming atoms explicitly would be important.
Also, TypeScript type information would be helpful.

### Storing an array of atom configs in atom

Finally, the atoms in atom pattern is to store an array of atom config into an atom.

```jsx
const countsAtom = atom([atom(1), atom(2), atom(3)])

const Counter = ({ countAtom }) => {
  const [count, setCount] = useAtom(countAtom)
  return (
    <div>
      {count} <button onClick={() => setCount((c) => c + 1)}>+1</button>
    </div>
  )
}

const Parent = () => {
  const [counts, setCounts] = useAtom(countsAtom)
  const addNewCount = () => {
    const newAtom = atom(0)
    setCounts((prev) => [...prev, newAtom])
  }
  return (
    <div>
      {counts.map((countAtom) => (
        <Counter countAtom={countAtom} key={countAtom} />
      ))}
      <button onClick={addNewCount}>Add</button>
    </div>
  )
}
```

The benefit of this approach is, if you increment a count,
only the corresponding Counter component re-renders and no other components re-render.

It is important to note that `anAtom.toString()` returns a unique id, which can be used as a `key` in a map.

#### Hint for TypeScript users

```jsx
<Counter countAtom={countAtom} key={`${countAtom}`} />
```

### Storing a map of atom configs in atom

Likewise, we can store an object map instead of an array.

```jsx
const pricesAtom = atom({
  apple: atom(15),
  orange: atom(12),
  pineapple: atom(25),
})

const Fruit = ({ name, priceAtom }) => {
  const [price] = useAtom(priceAtom)
  return (
    <div>
      {name}: {price}
    </div>
  )
}

const Parent = () => {
  const [prices] = useAtom(pricesAtom)
  return (
    <div>
      {Object.keys(prices).map((name) => (
        <Fruit name={name} priceAtom={prices[name]} key={name} />
      ))}
    </div>
  )
}
```


================================================
FILE: docs/guides/composing-atoms.mdx
================================================
---
title: Composing atoms
nav: 8.11
---

The `atom` function provided by library is very primitive,
but it's also so flexible that you can combine multiple atoms
to implement a functionality.

> Note again that `atom()` creates an atom config, which is an object
> to define a behavior of the atom.

Let's recap how we can derive an atom.

### Basic derived atoms

Here's one of the simplest examples of a derived atom:

```js
export const textAtom = atom('hello')
export const textLenAtom = atom((get) => get(textAtom).length)
```

The `textLenAtom` is called read-only atom, because
it doesn't have a `write` function defined.

The following is another simple example with the `write` function:

```js
const textAtom = atom('hello')
export const textUpperCaseAtom = atom(
  (get) => get(textAtom).toUpperCase(),
  (_get, set, newText) => set(textAtom, newText),
)
```

In this case, `textUpperCaseAtom` is capable to set the original `textAtom`.
So, we can only export `textUpperCaseAtom` and can hide
`textAtom` in a smaller scope.

Now, let's see some real examples.

### Overriding default atom values

Suppose we have a read-only atom.
Obviously read-only atoms are not writable, but we can combine two atoms
to override the read-only atom value.

```js
const rawNumberAtom = atom(10.1) // can be exported
const roundNumberAtom = atom((get) => Math.round(get(rawNumberAtom)))
const overwrittenAtom = atom(null)
export const numberAtom = atom(
  (get) => get(overwrittenAtom) ?? get(roundNumberAtom),
  (get, set, newValue) => {
    const nextValue =
      typeof newValue === 'function' ? newValue(get(numberAtom)) : newValue
    set(overwrittenAtom, nextValue)
  },
)
```

The final `numberAtom` just works like a normal primitive atom like `atom(10)`.
If you set a number value, it will override the `overwrittenAtom` value,
and if you set `null`, it will be the `roundNumberAtom` value.

The reusable implementation is available as `atomWithDefault`
in `jotai/utils`. See [atomWithDefault](../utilities/resettable.mdx).

Next, let's see another example to sync with external value.

### Syncing atom values with external values

There are some external values we want to deal with.
`localStorage` is the one. Another is `window.title`.

Let's see how to create an atom that is in sync with `localStorage`.

```js
const baseAtom = atom(localStorage.getItem('mykey') || '')
export const persistedAtom = atom(
  (get) => get(baseAtom),
  (get, set, newValue) => {
    const nextValue =
      typeof newValue === 'function' ? newValue(get(baseAtom)) : newValue
    set(baseAtom, nextValue)
    localStorage.setItem('mykey', nextValue)
  },
)
```

The `persistedAtom` works like a primitive atom, but its value
is persisted in `localStorage`.

The reusable implementation is available as `atomWithStorage`
in `jotai/utils`. See [atomWithStorage](../utilities/storage.mdx).

There is a caveat with this usage. While atom config doesn't hold a value,
the external value is a singleton value.
So, if we use this atom in two different Providers,
There will be an inconsistency between the two `persistedAtom` values.
This could be solved if the external value had a subscription mechanism.

For example, `atomWithProxy` in `jotai-valtio` comes with subscription,
so we don't have such a limitation. Values in different Providers
will be in sync.

Back to the main topic, let's explore another example.

### Extending atoms with `atomWith*` utils

We have several utils whose names start with `atomWith`.
They create an atom with a certain functionality.
Unfortunately, we can't combine two atom utils.
For example, `atomWithStorage` and `atomWithReducer`
can't be used to define a single atom.

In such a case, we need to derive an atom by ourselves.
Let's try adding reducer functionality to `atomWithStorage`:

```js
const reducer = ...
const baseAtom = atomWithStorage('mykey', '')
export const derivedAtom = atom(
  (get) => get(baseAtom),
  (get, set, action) => {
    set(baseAtom, reducer(get(baseAtom), action))
  }
)
```

This is easy, because in this case, `atomWithReducer`
is a simple implementation compared to `atomWithStorage`.

For more complex cases, it wouldn't be very easy.
It would still be a open research field.

Finally, let's see another example with actions.

### Action atoms

This should be known pattern as it's described in README.
Nonetheless, it might to be useful to revisit.

Let's create a counter that you can only increment or decrement by one.

One solution is `atomWithReducer`:

```js
const countAtom = atomWithReducer(0, (prev, action) => {
  if (action === 'INC') {
    return prev + 1
  }
  if (action === 'DEC') {
    return prev - 1
  }
  throw new Error('unknown action')
})
```

This is fine, but not very atomic.
If we want to get benefit from code splitting / lazy loading,
We want to create write only atoms, or action atoms.

```js
const baseAtom = atom(0) // do not export
export const countAtom = atom((get) => get(baseAtom)) // read only
export const incAtom = atom(null, (_get, set) => {
  set(baseAtom, (prev) => prev + 1)
})
export const decAtom = atom(null, (_get, set) => {
  set(baseAtom, (prev) => prev - 1)
})
```

This is more atomic and looks like a Jotai way.

You can also create an action atom that will call another action atom:

```js
// continued from the previous code
export const dispatchAtom = atom(null, (_get, set, action) => {
  if (action === 'INC') {
    set(incAtom)
  } else if (action === 'DEC') {
    set(decAtom)
  } else {
    throw new Error('unknown action')
  }
})
```

Why do we want it? Because it will be used only when needed.
It allows code splitting and dead code elimination.

### In summary

Atoms are building block.
By composing atoms based on other atoms,
we can implement complicated logic.
This is not only for read derived atoms, but also for write action atoms.

Essentially, atoms are like functions, so composing atoms is
like composing functions with other functions.

**Note**: We mentioned that our atoms can contain any kind of data, it can be a string, Blob, Observer, anything really. There is just one exception. Because derived atoms are defined using a function, Jotai will not understand if we pass it a function that isn't exactly a pure getter.
So what you can do is simply wrap your function in an object.

```js
const doublerAtom = atom({ callback: (n) => n * 2 })
// Usage
const [doubler] = useAtom(doublerAtom)
const doubledValue = doubler.callback(50) // Will compute to 100
```


================================================
FILE: docs/guides/core-internals.mdx
================================================
---
title: Core internals
description: A simplified version of the core implementation
nav: 8.10
---

This guide is beneficial for those who want to understand the core implementation of Jotai. It's not meant to be a complete example of the
core implementation but rather a simplified version. It's inspired by the collection of tweets by Daishi Kato([@dai_shi](https://twitter.com/dai_shi)).

### First Version

Let's start with an easy example. An atom is just a function that will return a configuration object. We are using WeakMap to map atom with their state.
WeakMap doesn't keep its keys in memory, so if an atom is garbage collected, its state will be garbage collected too. This helps avoid memory leaks.

```js
import { useState, useEffect } from 'react'

// atom function returns a config object which contains initial value
export const atom = (initialValue) => ({ init: initialValue })

// we need to keep track of the state of the atom.
// we are using weakmap to avoid memory leaks
const atomStateMap = new WeakMap()
const getAtomState = (atom) => {
  let atomState = atomStateMap.get(atom)
  if (!atomState) {
    atomState = { value: atom.init, listeners: new Set() }
    atomStateMap.set(atom, atomState)
  }
  return atomState
}

// useAtom hook returns a tuple of the current value
// and a function to update the atom's value
export const useAtom = (atom) => {
  const atomState = getAtomState(atom)
  const [value, setValue] = useState(atomState.value)
  useEffect(() => {
    const callback = () => setValue(atomState.value)

    // same atom can be used at multiple components, so we need to
    // keep listening for atom's state change till component is unmounted.
    atomState.listeners.add(callback)
    callback()
    return () => atomState.listeners.delete(callback)
  }, [atomState])

  const setAtom = (nextValue) => {
    atomState.value = nextValue

    // let all the subscribed components know that the atom's state has changed
    atomState.listeners.forEach((l) => l())
  }

  return [value, setAtom]
}
```

Here's an example using our simplified atom implementation. [Counter example](https://codesandbox.io/s/zealous-field-z2xk6?file=/src/App.js)

Ref tweet: [Demystifying the internal of jotai](https://twitter.com/dai_shi/status/1484835169475653634)

### Second Version

Hang on! We can do better. In Jotai, we can create derived atom. A derived atom is an atom that depends on other atoms.

```js
const priceAtom = atom(10)
const readOnlyAtom = atom((get) => get(priceAtom) * 2)
const writeOnlyAtom = atom(
  null, // it's a convention to pass `null` for the first argument
  (get, set, args) => {
    set(priceAtom, get(priceAtom) - args)
  },
)
const readWriteAtom = atom(
  (get) => get(priceAtom) * 2,
  (get, set, newPrice) => {
    set(priceAtom, newPrice / 2)
    // you can set as many atoms as you want at the same time
  },
)
```

To keep track of all the dependents, we need to add one more property to the atom's state. Let's say atom X depends on atom Y,
so when we update atom Y, we also update atom X. This is called dependency tracking.

```js
const atomState = {
  value: atom.init,
  listeners: new Set(),
  dependents: new Set(),
}
```

We now need to create functions for reading and writing an atom that can handle updating dependent atoms' state.

```js
import { useState, useEffect } from 'react'

export const atom = (read, write) => {
  if (typeof read === 'function') {
    return { read, write }
  }
  const config = {
    init: read,

    // get in the read function is to read the atom value.
    // It's reactive and read dependencies are tracked.
    read: (get) => get(config),

    // get in the write function is also to read atom value, but it's not tracked.
    // set in the write function is to write atom value and
    // it will invoke the write function of the target atom.
    write:
      write ||
      ((get, set, arg) => {
        if (typeof arg === 'function') {
          set(config, arg(get(config)))
        } else {
          set(config, arg)
        }
      }),
  }
  return config
}

// same as above but the state has one extra property: dependents
const atomStateMap = new WeakMap()
const getAtomState = (atom) => {
  let atomState = atomStateMap.get(atom)
  if (!atomState) {
    atomState = {
      value: atom.init,
      listeners: new Set(),
      dependents: new Set(),
    }
    atomStateMap.set(atom, atomState)
  }
  return atomState
}

// If atom is primitive, we return it's value.
// If atom is derived, we read the parent atom's value
// and add current atom to parent's the dependent set (recursively).
const readAtom = (atom) => {
  const atomState = getAtomState(atom)
  const get = (a) => {
    if (a === atom) {
      return atomState.value
    }
    const aState = getAtomState(a)
    aState.dependents.add(atom) // XXX add only
    return readAtom(a) // XXX no caching
  }
  const value = atom.read(get)
  atomState.value = value
  return value
}

// if atomState is modified, we need to notify all the dependent atoms (recursively)
// now run callbacks for all the components that are dependent on this atom
const notify = (atom) => {
  const atomState = getAtomState(atom)
  atomState.dependents.forEach((d) => {
    if (d !== atom) notify(d)
  })
  atomState.listeners.forEach((l) => l())
}

// writeAtom calls atom.write with the necessary params and triggers notify function
const writeAtom = (atom, value) => {
  const atomState = getAtomState(atom)

  // 'a' is some atom from atomStateMap
  const get = (a) => {
    const aState = getAtomState(a)
    return aState.value
  }

  // if 'a' is the same as atom, update the value, notify that atom and return
  // else calls writeAtom for 'a' (recursively)
  const set = (a, v) => {
    if (a === atom) {
      atomState.value = v
      notify(atom)
      return
    }
    writeAtom(a, v)
  }

  atom.write(get, set, value)
}

export const useAtom = (atom) => {
  const [value, setValue] = useState()
  useEffect(() => {
    const callback = () => setValue(readAtom(atom))
    const atomState = getAtomState(atom)
    atomState.listeners.add(callback)
    callback()
    return () => atomState.listeners.delete(callback)
  }, [atom])
  const setAtom = (nextValue) => {
    writeAtom(atom, nextValue)
  }
  return [value, setAtom]
}
```

Here is an example using our derived atom implementation. [Derived counter example](https://codesandbox.io/s/affectionate-chandrasekhar-nuxms?file=/src/App.js)

Ref tweet: [Supporting derived atoms](https://twitter.com/dai_shi/status/1485434083778117632)


================================================
FILE: docs/guides/debugging.mdx
================================================
---
title: Debugging
nav: 8.07
keywords: debug,labels,devtools,freeze
---

In basic apps, `console.log` can be our best friend for debugging atoms, but when applications get bigger and we have more atoms to use, logging would not be a good way of debugging atoms.
Jotai provides two ways of debugging atoms, **React Dev Tools** and **Redux Dev tools**. For reading values and simple debugging, React Dev Tools might suit you, but for more complicated tasks like Time-travelling and setting values, Redux Dev Tools would be a better option.

## Debug labels

It is worth mentioning that we have a concept called **Debug labels** in Jotai which may help us with debugging.
By default each Jotai state has the label like `1:<no debugLabel>` with number being internal `key` assigned to each atom automatically. But you can add labels to atoms to help you distinguish them more easily with `debugLabel`.

```js
const countAtom = atom(0)
// countAtom's debugLabel by default is 'atom1'
if (process.env.NODE_ENV !== 'production') {
  countAtom.debugLabel = 'count'
  // debugLabel is 'count' now
}
```

Jotai provides both a Babel and a SWC plugin, that adds a debugLabel automatically to every atom, which makes things easier for us. For more info, check out [jotai-babel](https://github.com/jotaijs/jotai-babel) and [@swc-jotai/debug-label](https://github.com/pmndrs/jotai/blob/main/docs/tools/swc.mdx)

## Using React Dev Tools

You can use [React Dev Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi)
to inspect Jotai state. To achieve that [useDebugValue](https://react.dev/reference/react/useDebugValue)
is used inside custom hooks. Keep in mind that it only works in dev mode
(such as `NODE_ENV === 'development'`).

### useAtom

`useAtom` calls `useDebugValue` for atom values, so if you select the component that consumes Jotai atoms in React Dev Tools, you would see "Atom" hooks for each atom that is used in the component along with the value it has right now.

### useAtomsDebugValue

`useAtomsDebugValue` catches all atoms in a component tree under Provider (or an entire tree for Provider-less mode), and `useDebugValue` for all atoms values.
If you navigate to the component that has `useAtomsDebugValue` in the React Dev Tools, we can see a custom hook "AtomsDebugValue" which allows you to see all atom values and their dependents.

One use case is to put the hook just under the `Provider` component:

```jsx
const DebugAtoms = () => {
  useAtomsDebugValue()
  return null
}

const Root = () => (
  <Provider>
    <DebugAtoms />
    <App />
  </Provider>
)
```

## Using Redux DevTools

You can also use [Redux DevTools](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd)
to inspect atoms, with many features like Time-travelling and value dispatching.

### [useAtomDevtools](https://jotai.org/docs/api/devtools#use-atom-devtools)

> `useAtomDevtools` is a React hook that manages ReduxDevTools extension for a particular atom.

If you have a specific atom in mind that you may want to debug, `useAtomDevtools` can be a good option.

```js
const countAtom = atom(0)
// setting countAtom.debugLabel is recommended if we have more atoms

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  useAtomDevtools(countAtom)
}
```

Now if we try `setCount`, we can see that the Redux Dev Tools logs those changes immediately.

![](https://lh3.googleusercontent.com/pw/AP1GczMgeYQOyCAc69gJIAcRBtKO9BOUEE3SQB5Bl-7IScJfChWGnVb3B0OmlhrjK8caQVnj-HtyN1cpv1l1K9kE4pxwapUwu_2OB-dO_G18ZUC1NbDJFiXYRW9jX8OeDBJeWg1Qx9_IdkfoaoIin90A8gSE=w828-h268-s-no-gm)
![]()

#### Time travel

Sometimes we need to switch to a specific value of our atoms' state, with Time travelling this is possible.
You can hover on each action you see in the devtools and see the **Jump** option there, with clicking it you'd be able to switch to that specific value.

#### Pause

If we don't record changes on atoms, we can stop watching those using the **Pausing** feature.

![](https://lh3.googleusercontent.com/pw/AP1GczP8hTBFtwlx0BJGGbbcXgfhMNG2Vz_uozdVnrTJHwMb1gKx55TP59WgvsMwgIyExwscgYZSpYDmxCJXjk_pKy6wP-K-0p287lkRXdTZEf074xUZr8fnIpkwg-zN14VXZ2STet1sVgTTawm49mc8Oygb=w395-h87-s-no-gm)

#### Dispatch

It's possible to set values on atoms with the **Dispatch** feature. You can do that by clicking on the **Show Dispatcher** button.
![](https://lh3.googleusercontent.com/pw/AP1GczMNn6aXTA7K8ZFzUj17I40cm0o7joOG6E76Q6UVnXYJ3TO7ItRI6Jr1EIxogfY9P2xkiQfyYqB7_aU--R_vdSyNXAtTfPuxxLymApRoZov0-6ZHS7mmxxxD4Ku1JnqTRyPyZaQHyQPkq8j4CciQaISV=w832-h149-s-no-gm)
This would set the `countAtoms`'s value to `5`.

> We should note that the value will be parsed by JSON.parse, so pass supported values.

### [useAtomsDevtools](../tools/devtools.mdx)

> `useAtomsDevtools` is a catch-all version of `useAtomDevtools` where it shows all atoms in the store instead of showing a specific one.

We'd recommend this hook if you want to keep track of all of your atoms in one place. It means every action on every atom that is placed in the bottom of this hook (in the React tree) will be caught by the Redux Dev Tools.

Every feature of `useAtomDevtools` is supported in this hook, but there's an extra feature, which includes giving more information about atoms dependents like:

```json
{
  "values": {
    "atom1:count": 0,
    "atom2:doubleCount": 0,
    "atom3:half": 0,
    "atom4:sum": 0
  },
  "dependents": {
    "atom1:count": ["atom1:count", "atom2:doubleCount", "atom4:sum"],
    "atom2:doubleCount": ["atom3:half", "atom4:sum"],
    "atom3:half": ["atom4:sum"],
    "atom4:sum": []
  }
}
```

## Frozen Atoms

To find bugs where you accidentally tried to mutate objects stored in atoms you
could use `freezeAtom` or `freezeAtomCreator`from `jotai/utils` bundle.
Which returns atoms value that is deeply freezed with `Object.freeze`.

### freezeAtom

```ts
freezeAtom(anAtom): AtomType
```

`freezeAtom` takes an existing atom and make it "frozen".
It returns the same atom.
The atom value will be deeply frozen by `Object.freeze`.
It is useful to find bugs where you unintentionally tried
to change objects (states) which can lead to unexpected behavior.
You may use `freezeAtom` with all atoms to prevent this situation.

#### Parameters

**anAtom** (required): An atom you wish to freeze.

#### Examples

```js
import { atom } from 'jotai'
import { freezeAtom } from 'jotai/utils'

const objAtom = freezeAtom(atom({ count: 0 }))
```

### freezeAtomCreator

If you need, you can define a factory for `freezeAtom`.

```ts
import { freezeAtom } from 'jotai/utils'

export function freezeAtomCreator<
  CreateAtom extends (...args: unknown[]) => Atom<unknown>,
>(createAtom: CreateAtom): CreateAtom {
  return ((...args: unknown[]) => freezeAtom(createAtom(...args))) as never
}
```


================================================
FILE: docs/guides/initialize-atom-on-render.mdx
================================================
---
title: Initializing state on render
description: How to initialize atom state on initial render
nav: 8.13
---

There are times when you need to create an reusable component which uses atoms.

These atoms' initial state are determined by the props passed to the component.

Below is a basic example illustrating how you can use `Provider` and its prop, `initialValues`, to initialize state.

### Basic Example

> CodeSandbox link: [codesandbox](https://codesandbox.io/s/init-atoms-with-usehydrateatoms-nryk1w).

Consider a basic example where you have a reusable `TextDisplay` component that allows you to display and update plain text.

This component has two child components, `PrettyText` and `UpdateTextInput`.

- `PrettyText` displays the text in blue.
- `UpdateTextInput` is an input field which updates the text value.

As opposed to passing `text` as a prop in the two child components, you decided that the `text` state should be shared between components as an atom.

To make `TextDisplay` component reusable, we take in a prop `initialTextValue`, which determines the initial state of the `text` atom.

To tie `initialTextValue` to `textAtom`, we wrap the child components in a component where we create a new store and pass it to a `Provider` component.

```jsx
const textAtom = atom('')

const PrettyText = () => {
  const [text] = useAtom(textAtom)
  return (
    <>
      <text
        style={{
          color: 'blue',
        }}
      >
        {text}
      </text>
    </>
  )
}

const UpdateTextInput = () => {
  const [text, setText] = useAtom(textAtom)
  const handleInputChange = (e) => {
    setText(e.target.value)
  }
  return (
    <>
      <input onChange={handleInputChange} value={text} />
    </>
  )
}

const HydrateAtoms = ({ initialValues, children }) => {
  // initialising on state with prop on render here
  useHydrateAtoms(initialValues)
  return children
}

export const TextDisplay = ({ initialTextValue }) => (
  <Provider>
    <HydrateAtoms initialValues={[[textAtom, initialTextValue]]}>
      <PrettyText />
      <br />
      <UpdateTextInput />
    </HydrateAtoms>
  </Provider>
)
```

Now, we can easily reuse `TextDisplay` component with different initial text values despite them referencing the "same" atom.

```jsx
export default function App() {
  return (
    <div className="App">
      <TextDisplay initialTextValue="initial text value 1" />

      <TextDisplay initialTextValue="initial text value 2" />
    </div>
  )
}
```

This behavior is due to our child components looking for the lowest common `Provider` ancestor to derive its value.

For more information on `Provider` behavior, please read the docs [here](../core/provider.mdx).

For more complex use cases, check out [Scope extension](../extensions/scope.mdx).

### Using Typescript

`useHydrateAtoms` has overloaded types and typescript cannot extract types from overloaded function. It is recommended to use a `Map` when passing initial atom values to the `useHydrateAtoms`.

Here is a working example:

```tsx
import type { ReactNode } from 'react'
import { Provider, atom, useAtomValue } from 'jotai'
import type { WritableAtom } from 'jotai'
import { useHydrateAtoms } from 'jotai/utils'

const testAtom = atom('')

export default function App() {
  return (
    <Provider>
      <AtomsHydrator atomValues={[[testAtom, 'hello']]}>
        <Component />
      </AtomsHydrator>
    </Provider>
  )
}

//This component contains all the states and the logic
function Component() {
  const testAtomValue = useAtomValue(testAtom)
  return <div>{testAtomValue}</div>
}

function AtomsHydrator({
  atomValues,
  children,
}: {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  atomValues: Iterable<
    readonly [WritableAtom<unknown, [any], unknown>, unknown]
  >
  children: ReactNode
}) {
  useHydrateAtoms(new Map(atomValues))
  return children
}
```


================================================
FILE: docs/guides/migrating-to-v2-api.mdx
================================================
---
title: v2 API migration
description: New "Async" API
nav: 8.0
---

RFC: https://github.com/pmndrs/jotai/discussions/1514

Jotai v1 is released at June 2022, and there has been various feedbacks.
React also proposes first-class support for promises.
Jotai v2 will have a new API.

Unfortunately, there are some breaking changes along with new features.

### What are new features

#### Vanilla library

Jotai comes with vanilla (non-React) functions
and React functions separately.
They are provided from alternate entry points like `jotai/vanilla`.

#### Store API

Jotai exposes store interface so that you can directly manipulate atom values.

```js
import { createStore } from 'jotai' // or from 'jotai/vanilla'

const store = createStore()
store.set(fooAtom, 'foo')

console.log(store.get(fooAtom)) // prints "foo"

const unsub = store.sub(fooAtom, () => {
  console.log('fooAtom value in store is changed')
})
// call unsub() to unsubscribe.
```

You can also create your own React Context to pass a store.

#### More flexible atom `write` function

The write function can accept multiple arguments,
and return a value.

```js
atom(
  (get) => get(...),
  (get, set, arg1, arg2, ...) => {
    ...
    return someValue
  }
)
```

### What are breaking

#### Async atoms are no longer special

Async atoms are just normal atoms with promise values.
Atoms getter functions don't resolve promises.
On the other hand, `useAtom` hook continues to resolve promises.

Some utils like `splitAtom` expects sync atoms,
and won't work with async atoms.

#### Writable atom type is changed (TypeScript only)

```ts
// Old
WritableAtom<Value, Arg, Result extends void | Promise<void>>

// New
WritableAtom<Value, Args extends unknown[], Result>
```

In general, we should avoid using `WritableAtom` type directly.

#### Some functions are dropped

- Provider's `initialValues` prop is removed, because `store` is more flexible.
- Provider's scope props is removed, because you can create own context.
- `abortableAtom` util is removed, because the feature is included by default
- `waitForAll` util is removed, because `Promise.all` just works

### Migration guides

#### Async atoms

`get` function for read function of async atoms
doesn't resolve promises, so you have to put `await` or `.then()`.

In short, the change is something like the following.
(If you are TypeScript users, types will tell where to changes.)

##### Previous API

```js
const asyncAtom = atom(async () => 'hello')
const derivedAtom = atom((get) => get(asyncAtom).toUppercase())
```

##### New API

```js
const asyncAtom = atom(async () => 'hello')
const derivedAtom = atom(async (get) => (await get(asyncAtom)).toUppercase())
// or
const derivedAtom = atom((get) => get(asyncAtom).then((x) => x.toUppercase()))
```

#### Provider's `initialValues` prop

##### Previous API

```jsx
const countAtom = atom(0)

  // in component
  <Provider initialValues={[[countAtom, 1]]}>
    ...
```

##### New API

```jsx
const countAtom = atom(0)

const HydrateAtoms = ({ initialValues, children }) => {
  useHydrateAtoms(initialValues)
  return children
}

  // in component
  <Provider>
    <HydrateAtoms initialValues={[[countAtom, 1]]}>
      ...
```

#### Provider's `scope` prop

##### Previous API

```jsx
const myScope = Symbol()

  // Parent component
  <Provider scope={myScope}>
    ...
  </Provider>

  // Child component
  useAtom(..., myScope)
```

##### New API

```jsx
const MyContext = createContext()
const store = createStore()

  // Parent component
  <MyContext.Provider value={store}>
    ...
  </MyContext.Provider>

  // Child Component
  const store = useContext(MyContext)
  useAtom(..., { store })
```

#### `abortableAtom` util

You no longer need the previous `abortableAtom` util,
because it's now supported with the normal `atom`.

##### Previous API

```js
const asyncAtom = abortableAtom(async (get, { signal }) => {
 ...
}
```

##### New API

```js
const asyncAtom = atom(async (get, { signal }) => {
  ...
}
```

#### `waitForAll` util

You no longer need the previous `waitForAll` util,
because we can use native Promise APIs.

##### Previous API

```js
const allAtom = waitForAll([fooAtom, barAtom])
```

##### New API

```js
const allAtom = atom((get) => Promise.all([get(fooAtom), get(barAtom)]))
```

Note that creating an atom in render function can cause [infinite loop](../core/atom.mdx#note-about-creating-an-atom-in-render-function)

#### `splitAtom` util (or some other utils) with async atoms

`splitAtom` util only accepts sync atoms.
You need to unwrap async atoms before passing.

This applies to some other utils like `atomsWithQuery` from `jotai-tanstack-query`.

##### Previous API

```js
const splittedAtom = splitAtom(asyncArrayAtom)
```

##### New API

```js
const splittedAtom = splitAtom(unwrap(asyncArrayAtom, () => []))
```

As of writing, `unwrap` is unstable and not documented.
You can instead use `loadable`, which gives more control on loading status.
If you need to use `<Suspense>`, atoms-in-atom pattern would help.

For more information, refer the following discussions:

- https://github.com/pmndrs/jotai/discussions/1615
- https://github.com/jotaijs/jotai-tanstack-query/issues/21
- https://github.com/pmndrs/jotai/discussions/1751

### Some other changes

#### Utils

- `atomWithStorage` util's `delayInit` is removed as being default. Also it will always render `initialValue` on first render, and the stored value, if any, on subsequent renders. The new behavior differs from v1. See https://github.com/pmndrs/jotai/discussions/1737 for more information.
- `useHydrateAtoms` can only accept writable atoms.

#### Import statements

The v2 API is also provided from alternate entry points for library authors and non-React users.

- `jotai/vanilla`
- `jotai/vanilla/utils`
- `jotai/react`
- `jotai/react/utils`

```js
// Available since v1.11.0
import { atom } from 'jotai/vanilla'
import { useAtom } from 'jotai/react'

// Available since v2.0.0
import { atom } from 'jotai' // is same as 'jotai/vanilla'
import { useAtom } from 'jotai' // is same as 'jotai/react'
```

Note: If you are not using ESM, you want to prefer using `jotai/vanilla` etc. instead of `jotai`, for better tree shaking.


================================================
FILE: docs/guides/nextjs.mdx
================================================
---
title: Next.js
description: How to use Jotai with Next.js
nav: 8.03
keywords: next,nextjs
---

### Hydration

Jotai has support for hydration of atoms with `useHydrateAtoms`. The documentation for the hook can be seen [here](../utilities/ssr.mdx).

### Sync with router

It's possible to sync Jotai with the router. You can achieve this with `atomWithHash`:

```js
const pageAtom = atomWithHash('page', 1, {
  replaceState: true,
  subscribe: (callback) => {
    Router.events.on('routeChangeComplete', callback)
    window.addEventListener('hashchange', callback)
    return () => {
      Router.events.off('routeChangeComplete', callback)
      window.removeEventListener('hashchange', callback)
    }
  },
})
```

This way you have full control over what [router event](https://nextjs.org/docs/api-reference/next/router#routerevents) you want to subscribe to.

> #### In Next.js 13
>
> As of Next.js 13 there have been some changes to the `Router.events.on()` which no longer expose events. There are plans in the [App Router Roadmap](https://beta.nextjs.org/docs/app-directory-roadmap#planned-features) for event intercepting and hash handling. However there is no ETA on when this will be available or what it will look like. For now when trying to the `atomWithHash()` you will not get the atom loading with any data when navigating using the router, only when the page is reloaded or the component is rerendered. It is also recommended that you set the `setHash` option to `replaceState` as Next.js appears to use window.history in the background and this will allow the user to use the browser back button.

### You can't return promises in server side rendering

It's important to note that you can't return promises with SSR - However, it's possible to guard against it inside the atom definition.

If possible use `useHydrateAtoms` to hydrate values from the server.

```js
const postData = atom((get) => {
  const id = get(postId)
  if (isSSR || prefetchedPostData[id]) {
    return prefetchedPostData[id] || EMPTY_POST_DATA
  }
  return fetchData(id) // returns a promise
})
```

### Provider

By default, Jotai uses an implicit global store to keep track of atom values. This is what is referred to as "provider-less" mode. This becomes an issue in SSR scenario because this global store is kept alive and is shared between multiple requests, which can lead to bugs and security risks.

To limit the lifetime of the store to the scope of one request, you need to use a [Provider](../core/provider.mdx) at the root of your app (or a subtree if you're using Jotai only for a part of your application).

```typescript
import { Provider } from 'jotai'

function App({ Component, pageProps }: AppProps) {
  return (
    <Provider>
      <Component {...pageProps} />
    </Provider>
  )
}
```

In this case:

1. `Provider` will hold the state of the atoms used in its subtree instead of the global store.
2. `Provider`'s lifetime will be the same as the app itself, and since the app is recreated on each SSR request we essentially limit the lifetime of the store to a single request as well.

### SWC plugins

Jotai provides SWC plugins for better DX while developing with Next.js. [Find more info in the SWC section.](../tools/swc.mdx)

### Examples

#### Clock

<Stackblitz
  id="stackblitz-starters-nsugnt"
  file="store%2Findex.ts,components%2FClock.tsx"
/>

#### HN Posts

Page Router demo:

<Stackblitz
  id="stackblitz-starters-cnz9lg"
  file="store%2Findex.ts,pages%2F_app.tsx,pages%2Findex.tsx"
/>

App Router [demo on Stackblitz](https://stackblitz.com/edit/jotai-nextjs-app-router-demo?file=store%2Findex.ts,app%2Flayout.tsx,components%2FPost.tsx,app%2Fpage.tsx)

#### Next.js repo

```bash
npx create-next-app --example with-jotai with-jotai-app
```

Here's a [link](https://github.com/vercel/next.js/tree/canary/examples/with-jotai).


================================================
FILE: docs/guides/performance.mdx
================================================
---
title: Performance
description: How to limit extra re-renders
nav: 8.08
keywords: performance
---

**Note**: This guide has room for improvement. Consider it as FYI for now.

Jotai & React gives us quite a few tools to manage the re-renders that happen in the app lifecycle.
First, please read about the difference [between render & commit](https://legacy.reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#browsing-commits), because that's very important to understand before going further.

### Cheap renders

As seen in the [core section](../core/atom.mdx), due to React 18 default behaviour (but overall good practice), you have to make sure your component functions are _idempotent_.
They will be called multiple times during the render phase, even at mount. So we need to keep our renders cheap at all cost!

#### Heavy computation

Always make heavy computation outside of the React lifecycle (in actions for example)

Dont's:

```js
// Heavy computation for each item
const selector = (s) => s.filter(heavyComputation)
const Profile = () => {
  const [computed] = useAtom(selectAtom(friendsAtom, selector))
}
```

Do's:

```js
const friendsAtom = atom([])
const fetchFriendsAtom = atom(null, async (get, set, payload) => {
  // Fetch all friends
  const res = await fetch('https://jsonplaceholder.typicode.com/users')
  const data = await res.json()

  // Make heavy computation once only
  const computed = data.filter(heavyComputation)
  set(friendsAtom, computed)
})
// Usage in components
const Profile = () => {
  const [friends] = useAtom(friendsAtom)
}
```

#### Small components

Observed atoms should only re-render small parts of your application that required an update. The less comparison React has to make, the shorter your render time will be.

Dont's:

```jsx
const Profile = () => {
  const [name] = useAtom(nameAtom)
  const [age] = useAtom(ageAtom)
  return (
    <>
      <div>{name}</div>
      <div>{age}</div>
    </>
  )
}
```

Do's:

```jsx
const NameComponent = () => {
  const [name] = useAtom(nameAtom)
  return <div>{name}</div>
}
const AgeComponent = () => {
  const [age] = useAtom(ageAtom)
  return <div>{age}</div>
}
const Profile = () => {
  return (
    <>
      <NameComponent />
      <AgeComponent />
    </>
  )
}
```

### Render on demand

Usually, the main performance overhead will come from re-rendering parts of your app that did not need to, or way more than they should.

We have a few tools to deal with "when" React should render our components. If you have not seen the usage of `useMemo` and `useCallback`, please check the official React documentation for more info before going further.
They are of great use to reduce un-necessary renders where your app is not fluid.

But Jotai also provides its set of tools to handle the "when" our atoms should trigger a re-render.

- Out of the box, Jotai encourages you to split your data into atomic parts, hence each atom is stored separately and will only trigger a re-render when their own value change
- `selectAtom` allows you to subscribe to specific part of a large object and only re-render on value change
- `focusAtom` same as selectAtom, but creating a new atom for the part, giving a setter to update that specific part easily
- `splitAtom` does the work of selectAtom/focusAtom for a dynamic list

While this seems simplistic, it is simple to reason about. That was the goal, let's keep it simple to keep it fast.

#### Frequent or rare updates

Ask yourself whether your atom is usually going to be frequently update or more rarely.
Let's imagine an atom containing an object that changes almost every second, it may not be best suited to "focus" on a specific properties of this object using `focusAtom`, because anyway they will all re-render in the same time, so best adding no overhead and not create any more atoms.

On the other hand, if your object has properties that rarely change, and most importantly, that change independently from the other properties, then you may want to use `focusAtom` or `selectAtom` to prevent un-necessary renders.


================================================
FILE: docs/guides/persistence.mdx
================================================
---
title: Persistence
description: How to persist atoms
nav: 8.14
---

Jotai has an [atomWithStorage function in the utils bundle](../utilities/storage.mdx) for persistence that supports persisting state in `sessionStorage`, `localStorage`, `AsyncStorage`, or the URL hash.

(Note: This guide is a bit outdated and requires some rewrites.)

There are also several alternate implementations here:

### A simple pattern with localStorage

```js
const strAtom = atom(localStorage.getItem('myKey') ?? 'foo')

const strAtomWithPersistence = atom(
  (get) => get(strAtom),
  (get, set, newStr) => {
    set(strAtom, newStr)
    localStorage.setItem('myKey', newStr)
  },
)
```

### A helper function with localStorage and JSON parse

```js
const atomWithLocalStorage = (key, initialValue) => {
  const getInitialValue = () => {
    const item = localStorage.getItem(key)
    if (item !== null) {
      return JSON.parse(item)
    }
    return initialValue
  }
  const baseAtom = atom(getInitialValue())
  const derivedAtom = atom(
    (get) => get(baseAtom),
    (get, set, update) => {
      const nextValue =
        typeof update === 'function' ? update(get(baseAtom)) : update
      set(baseAtom, nextValue)
      localStorage.setItem(key, JSON.stringify(nextValue))
    },
  )
  return derivedAtom
}
```

(Error handling should be added.)

### A helper function with AsyncStorage and JSON parse

This requires [onMount](../core/atom.mdx#onmount-property).

```js
const atomWithAsyncStorage = (key, initialValue) => {
  const baseAtom = atom(initialValue)
  baseAtom.onMount = (setValue) => {
    ;(async () => {
      const item = await AsyncStorage.getItem(key)
      setValue(JSON.parse(item))
    })()
  }
  const derivedAtom = atom(
    (get) => get(baseAtom),
    (get, set, update) => {
      const nextValue =
        typeof update === 'function' ? update(get(baseAtom)) : update
      set(baseAtom, nextValue)
      AsyncStorage.setItem(key, JSON.stringify(nextValue))
    },
  )
  return derivedAtom
}
```

Don't forget to check out the [Async documentation](../guides/async.mdx) for more details on how to use async atoms.

### Example with sessionStorage

Same as AsyncStorage, just use `atomWithStorage` util and override the default storage with the `sessionStorage`

```js
import { atomWithStorage, createJSONStorage } from 'jotai/utils'

const storage = createJSONStorage(() => sessionStorage)
const someAtom = atomWithStorage('some-key', someInitialValue, storage)
```

### A serialize atom pattern

```tsx
type Actions =
  | { type: 'serialize'; callback: (value: string) => void }
  | { type: 'deserialize'; value: string }

const serializeAtom = atom(null, (get, set, action: Actions) => {
  if (action.type === 'serialize') {
    const obj = {
      todos: get(todosAtom).map(get),
    }
    action.callback(JSON.stringify(obj))
  } else if (action.type === 'deserialize') {
    const obj = JSON.parse(action.value)
    // needs error handling and type checking
    set(
      todosAtom,
      obj.todos.map((todo: Todo) => atom(todo)),
    )
  }
})

const Persist = () => {
  const [, dispatch] = useAtom(serializeAtom)
  const save = () => {
    dispatch({
      type: 'serialize',
      callback: (value) => {
        localStorage.setItem('serializedTodos', value)
      },
    })
  }
  const load = () => {
    const value = localStorage.getItem('serializedTodos')
    if (value) {
      dispatch({ type: 'deserialize', value })
    }
  }
  return (
    <div>
      <button onClick={save}>Save to localStorage</button>
      <button onClick={load}>Load from localStorage</button>
    </div>
  )
}
```

#### Examples

<Stackblitz id="vitejs-vite-zda5uw" file="src%2FApp.tsx" />

### A pattern with atomFamily

```tsx
type Actions =
  | { type: 'serialize'; callback: (value: string) => void }
  | { type: 'deserialize'; value: string }

const serializeAtom = atom(null, (get, set, action: Actions) => {
  if (action.type === 'serialize') {
    const todos = get(todosAtom)
    const todoMap: Record<string, { title: string; completed: boolean }> = {}
    todos.forEach((id) => {
      todoMap[id] = get(todoAtomFamily({ id }))
    })
    const obj = {
      todos,
      todoMap,
      filter: get(filterAtom),
    }
    action.callback(JSON.stringify(obj))
  } else if (action.type === 'deserialize') {
    const obj = JSON.parse(action.value)
    // needs error handling and type checking
    set(filterAtom, obj.filter)
    obj.todos.forEach((id: string) => {
      const todo = obj.todoMap[id]
      set(todoAtomFamily({ id, ...todo }), todo)
    })
    set(todosAtom, obj.todos)
  }
})

const Persist = () => {
  const [, dispatch] = useAtom(serializeAtom)
  const save = () => {
    dispatch({
      type: 'serialize',
      callback: (value) => {
        localStorage.setItem('serializedTodos', value)
      },
    })
  }
  const load = () => {
    const value = localStorage.getItem('serializedTodos')
    if (value) {
      dispatch({ type: 'deserialize', value })
    }
  }
  return (
    <div>
      <button onClick={save}>Save to localStorage</button>
      <button onClick={load}>Load from localStorage</button>
    </div>
  )
}
```

#### Examples

<Stackblitz id="vitejs-vite-z4kjv3" file="src%2FApp.tsx" />


================================================
FILE: docs/guides/react-native.mdx
================================================
---
title: React Native
description: Using Jotai in React Native
nav: 8.06
keywords: native,ios,android
---

Jotai atoms can be used in React Native applications with absolutely no changes.
Our goal is to always be 100% compatible with React-Native.

### Persistence

When it comes to persistence feature, the implementation specific to React Native are detailed in the [atomWithStorage function in the utils bundle](../utilities/storage.mdx).

### Performance

There is no known specific overhead when using Jotai in your app. Some libraries will add some/lots of additional properties and methods to the stored data for the practical usage, but Jotai behaves differently and you're always manipulating simple stuff that could barely be shortcuted.

Jotai atomic architecture will encourage you to split logic and data, providing a top-most experience to control every one of your render ([or commits, to be precise](https://legacy.reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html#browsing-commits)) and therefore reach the best performances.

And always remember that renders have to be fast, split calculation logic to async actions.


================================================
FILE: docs/guides/remix.mdx
================================================
---
title: Remix
description: How to use Jotai with Remix
nav: 8.05
keywords: remix
status: draft
---

### Hydration

Jotai has support for hydration of atoms with `useHydrateAtoms`. The documentation for the hook can be seen [here](../utilities/ssr.mdx).


================================================
FILE: docs/guides/resettable.mdx
================================================
---
title: Resettable
description: How to use resettable atoms
nav: 8.99
published: false
---

The Jotai core doesn't support resettable atoms.
But you can create those with helper functions from `jotai/utils`.

### Primitive resettable atom with atomWithReset / useResetAtom

```jsx
import { useAtom } from 'jotai'
import { atomWithReset, useResetAtom } from 'jotai/utils'

const todoListAtom = atomWithReset([
  { description: 'Add a todo', checked: false },
])

const TodoList = () => {
  const [todoList, setTodoList] = useAtom(todoListAtom)
  const resetTodoList = useResetAtom(todoListAtom)

  return (
    <>
      <ul>
        {todoList.map((todo) => (
          <li>{todo.description}</li>
        ))}
      </ul>

      <button
        onClick={() =>
          setTodoList((l) => [
            ...l,
            {
              description: `New todo ${new Date().toDateString()}`,
              checked: false,
            },
          ])
        }
      >
        Add todo
      </button>
      <button onClick={resetTodoList}>Reset</button>
    </>
  )
}
```

### Examples

<Stackblitz id="vitejs-vite-2s1vg6" file="src%2FApp.tsx" />

### Derived atom with RESET symbol

```jsx
import { atom, useAtom, useSetAtom } from 'jotai'
import { atomWithReset, useResetAtom, RESET } from 'jotai/utils'

const dollarsAtom = atomWithReset(0)
const centsAtom = atom(
  (get) => get(dollarsAtom) * 100,
  (get, set, newValue: number | typeof RESET) =>
    set(dollarsAtom, newValue === RESET ? newValue : newValue / 100)
)

const ResetExample = () => {
  const [dollars] = useAtom(dollarsAtom)
  const setCents = useSetAtom(centsAtom)
  const resetCents = useResetAtom(centsAtom)

  return (
    <>
      <h3>Current balance ${dollars}</h3>
      <button onClick={() => setCents(100)}>Set $1</button>
      <button onClick={() => setCents(200)}>Set $2</button>
      <button onClick={resetCents}>Reset</button>
    </>
  )
}
```

### Examples

<Stackblitz id="vitejs-vite-wjgquh" file="src%2FApp.tsx" />


================================================
FILE: docs/guides/testing.mdx
================================================
---
title: Testing
description: How to test your code using Jotai
nav: 8.09
keywords: test,testing
---

We echo the [guiding principles of Testing library](https://testing-library.com/docs/guiding-principles/):

- "The more your tests resemble the way your software is used, the more confidence they can give you."

We encourage you to write tests, like the user would interact with your atoms and components,
therefore treating Jotai as an implementation detail.

Here's an example using [React testing library](https://github.com/testing-library/react-testing-library):

`Counter.tsx`:

```jsx
import { atom, useAtom } from 'jotai'

export const countAtom = atom(0)

export function Counter() {
  const [count, setCount] = useAtom(countAtom)
  return (
    <h1>
      <p>{count}</p>
      <button onClick={() => setCount((c) => c + 1)}>one up</button>
    </h1>
  )
}
```

`Counter.test.ts`:

```jsx
import React from 'react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Counter } from './Counter'

test('should increment counter', () => {
  // Arrange
  render(<Counter />)

  const counter = screen.getByText('0')
  const incrementButton = screen.getByText('one up')
  // Act
  await userEvent.click(incrementButton)
  // Assert
  expect(counter.textContent).toEqual('1')
})
```

### Injected Values

You may want to inject arbitrary values to your atom before starting some tests.
Maybe the counter should be limited to 100. Let's see how to test that it doesn't increase after reaching 100.
In order to do that, simply use a [Provider](../core/provider.mdx), and export your atom to be filled-in.

```tsx
import React from 'react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useHydrateAtoms } from 'jotai/utils'
import { countAtom, Counter } from './Counter'
import { Provider } from 'jotai'

const HydrateAtoms = ({ initialValues, children }) => {
  useHydrateAtoms(initialValues)
  return children
}

const TestProvider = ({ initialValues, children }) => (
  <Provider>
    <HydrateAtoms initialValues={initialValues}>{children}</HydrateAtoms>
  </Provider>
)

const CounterProvider = () => {
  return (
    <TestProvider initialValues={[[countAtom, 100]]}>
      <Counter />
    </TestProvider>
  )
}

test('should not increment on max (100)', () => {
  render(<CounterProvider />)

  const counter = screen.getByText('100')
  const incrementButton = screen.getByText('one up')
  await userEvent.click(incrementButton)
  expect(counter.textContent).toEqual('100')
})
```

### Custom hooks

If you have complex atoms, sometimes you want to test them in isolation.

For that, you can use [React Hooks Testing Library](https://github.com/testing-library/react-hooks-testing-library).
Here's an example below:

`countAtom.ts`:

```ts
import { useAtom } from 'jotai'
import { atomWithReducer } from 'jotai/utils'

const reducer = (state: number, action?: 'INCREASE' | 'DECREASE') => {
  switch (action) {
    case 'INCREASE':
      return state + 1
    case 'DECREASE':
      return state - 1
    case undefined:
      return state
  }
}
export const countAtom = atomWithReducer(0, reducer)
```

`countAtom.test.ts`:

```ts
import { renderHook, act } from '@testing-library/react-hooks'
import { useAtom } from 'jotai'
import { countAtom } from './countAtom'

test('should increment counter', () => {
  const { result } = renderHook(() => useAtom(countAtom))

  act(() => {
    result.current[1]('INCREASE')
  })

  expect(result.current[0]).toBe(1)
})
```

### Example with React-Native

Of course, you can test React-Native components too the same way, with or without `Provider`.

```tsx
import React from 'react'
import { render, fireEvent } from '@testing-library/react-native'
import { Counter } from './counter'

test('should increment counter', () => {
  // Arrange
  const { getByText } = render(<Counter />)
  const counter = getByText('0')
  const incrementButton = getByText('one up')
  // Act
  fireEvent.press(incrementButton)
  // Assert
  expect(counter.props.children.toString()).toEqual('1')
})
```


================================================
FILE: docs/guides/typescript.mdx
================================================
---
title: TypeScript
description: How to use Jotai with TypeScript
nav: 8.02
keywords: typescript,types
---

### Version requirement

Jotai uses TypeScript 3.8+ syntax. Upgrade your TypeScript version if you're on 3.7.5 or lower.

Jotai relies heavily on type inferences and requires `strictNullChecks` to be enabled. Consider adding `"strict": true` in your tsconfig.json.
[#550](https://github.com/pmndrs/jotai/issues/550)
[#802](https://github.com/pmndrs/jotai/issues/802)
[#838](https://github.com/pmndrs/jotai/issues/838)

### Notes

#### Primitive atoms are basically type inferred

```ts
const numAtom = atom(0) // primitive number atom
const strAtom = atom('') // primitive string atom
```

### Primitive atoms can be explicitly typed

```ts
const numAtom = atom<number>(0)
const numAtom = atom<number | null>(0)
const arrAtom = atom<string[]>([])
```

#### Derived atoms can mostly have their types inferred

In general, this is the recommended approach since typing derived
atoms can get a little confusing, particularly for those who are
doing it for the first time.

```ts

# Read only derived atoms
const readOnlyAtom = atom((get) => get(numAtom))
const asyncReadOnlyAtom = atom(async (get) => await get(someAsyncAtom))

# Write only atoms
const writeOnlyAtom = atom(null, (_get, set, str: string) => set(fooAtom, str))
const multipleArgumentsAtom = atom(
  null,
  (_get, set, valueOne: number, valueTwo: number) =>
    set(fooAtom, Math.max(valueOne, valueTwo))
);

# Read/Write atoms
const readWriteAtom = atom(
  (get) => get(strAtom),
  (_get, set, num: number) => set(strAtom, String(num))
)
const asyncReadWriteAtom = atom(
  async (get) => await get(asyncStrAtom),
  (_get, set, num: number) => set(strAtom, String(num))
)
```

#### Derived atoms can also be explicitly typed

If you encounter a situation where you need or want to explicitly
type your derived atoms, you can do that as well.

```ts
const asyncStrAtom = atom<Promise<string>>(async () => 'foo')

/**
 * For write only atoms you'll need to supply three type parameters.
 * The first type parameter describes the value returned from the atom. In the following example this is `null`.
 * The second type parameter describes the arguments (plural) you will pass to the "write" function. Even if you only
 * plan to have one argument, this type must be an array as show in the example.
 * The third type parameter describes the return value of the "write" function. Normally, there is no return value,
 * which is why we use `void` in the example below.
 */
const writeOnlyAtom = atom<null, [string, number], void>(
  null,
  (_get, set, stringValue, numberValue) => set(fooAtom, stringValue),
)

/**
 * Read/Write atoms also take the same three type parameters.
 * Just for the sake of completeness, in this example, we show that the first type parameter
 * can also describe an async atom.
 */
const readWriteAtom = atom<Promise<string>, [number], void>(
  async (get) => await get(asyncStrAtom),
  (_get, set, num) => set(strAtom, String(num)),
)
```

#### useAtom is typed based on atom types

```ts
const [num, setNum] = useAtom(primitiveNumAtom)
const [num] = useAtom(readOnlyNumAtom)
const [, setNum] = useAtom(writeOnlyNumAtom)
```

#### Access to the value type of an atom

```ts
import { ExtractAtomValue, useAtomValue } from 'jotai'
import { userAtom } from 'state'
import { useQuery } from '@tanstack/react-query'

export default function WriteReview(hid) {
  const user = useAtomValue(userAtom)
  const res = useGetReviewQuery(user)
}

function useGetReviewQuery(user: ExtractAtomValue<typeof userAtom>) {
  return fetch('/api/user/' + user.id + '/review')
}
```


================================================
FILE: docs/guides/using-store-outside-react.mdx
================================================
---
title: Using store outside React
description: Using store outside
Download .txt
gitextract_mot3st09/

├── .codesandbox/
│   └── ci.json
├── .github/
│   ├── DISCUSSION_TEMPLATE/
│   │   └── bug-report.yml
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── config.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── compressed-size.yml
│       ├── ecosystem-ci.yml
│       ├── livecodes-post-comment.yml
│       ├── livecodes-preview.yml
│       ├── preview-release.yml
│       ├── publish.yml
│       ├── stale-discussions.yml
│       ├── test-multiple-builds.yml
│       ├── test-multiple-versions.yml
│       ├── test-old-typescript.yml
│       └── test.yml
├── .gitignore
├── .livecodes/
│   └── react.json
├── .prettierignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── babel.config.mjs
├── benchmarks/
│   ├── .gitignore
│   ├── simple-read.ts
│   ├── simple-write.ts
│   └── subscribe-write.ts
├── docs/
│   ├── basics/
│   │   ├── comparison.mdx
│   │   ├── concepts.mdx
│   │   ├── functional-programming-and-jotai.mdx
│   │   └── showcase.mdx
│   ├── core/
│   │   ├── atom.mdx
│   │   ├── provider.mdx
│   │   ├── store.mdx
│   │   └── use-atom.mdx
│   ├── extensions/
│   │   ├── cache.mdx
│   │   ├── effect.mdx
│   │   ├── immer.mdx
│   │   ├── location.mdx
│   │   ├── optics.mdx
│   │   ├── query.mdx
│   │   ├── redux.mdx
│   │   ├── relay.mdx
│   │   ├── scope.mdx
│   │   ├── trpc.mdx
│   │   ├── urql.mdx
│   │   ├── valtio.mdx
│   │   ├── xstate.mdx
│   │   └── zustand.mdx
│   ├── guides/
│   │   ├── async.mdx
│   │   ├── atoms-in-atom.mdx
│   │   ├── composing-atoms.mdx
│   │   ├── core-internals.mdx
│   │   ├── debugging.mdx
│   │   ├── initialize-atom-on-render.mdx
│   │   ├── migrating-to-v2-api.mdx
│   │   ├── nextjs.mdx
│   │   ├── performance.mdx
│   │   ├── persistence.mdx
│   │   ├── react-native.mdx
│   │   ├── remix.mdx
│   │   ├── resettable.mdx
│   │   ├── testing.mdx
│   │   ├── typescript.mdx
│   │   ├── using-store-outside-react.mdx
│   │   ├── vite.mdx
│   │   └── waku.mdx
│   ├── index.mdx
│   ├── recipes/
│   │   ├── atom-with-broadcast.mdx
│   │   ├── atom-with-compare.mdx
│   │   ├── atom-with-debounce.mdx
│   │   ├── atom-with-listeners.mdx
│   │   ├── atom-with-refresh-and-default.mdx
│   │   ├── atom-with-refresh.mdx
│   │   ├── atom-with-toggle-and-storage.mdx
│   │   ├── atom-with-toggle.mdx
│   │   ├── custom-useatom-hooks.mdx
│   │   ├── large-objects.mdx
│   │   ├── use-atom-effect.mdx
│   │   └── use-reducer-atom.mdx
│   ├── third-party/
│   │   ├── bunja.mdx
│   │   ├── derive.mdx
│   │   └── history.mdx
│   ├── tools/
│   │   ├── babel.mdx
│   │   ├── devtools.mdx
│   │   └── swc.mdx
│   └── utilities/
│       ├── async.mdx
│       ├── callback.mdx
│       ├── family.mdx
│       ├── lazy.mdx
│       ├── reducer.mdx
│       ├── resettable.mdx
│       ├── select.mdx
│       ├── split.mdx
│       ├── ssr.mdx
│       └── storage.mdx
├── eslint.config.mjs
├── examples/
│   ├── hacker_news/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── index.tsx
│   │   │   ├── styles.css
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── hello/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── index.tsx
│   │   │   ├── prism.css
│   │   │   ├── style.css
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── mega-form/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── index.tsx
│   │   │   ├── initialValue.ts
│   │   │   ├── style.css
│   │   │   ├── useAtomSlice.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── starter/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── index.css
│   │   │   ├── index.tsx
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── text_length/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── index.tsx
│   │   │   └── react-app-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── todos/
│   │   ├── README.md
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── index.tsx
│   │   │   ├── styles.css
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   └── todos_with_atomFamily/
│       ├── README.md
│       ├── index.html
│       ├── package.json
│       ├── public/
│       │   └── index.html
│       ├── src/
│       │   ├── App.tsx
│       │   ├── index.tsx
│       │   ├── styles.css
│       │   └── vite-env.d.ts
│       ├── tsconfig.json
│       └── vite.config.ts
├── package.json
├── pnpm-workspace.yaml
├── rollup.config.mjs
├── src/
│   ├── babel/
│   │   ├── plugin-debug-label.ts
│   │   ├── plugin-react-refresh.ts
│   │   ├── preset.ts
│   │   └── utils.ts
│   ├── index.ts
│   ├── react/
│   │   ├── Provider.ts
│   │   ├── useAtom.ts
│   │   ├── useAtomValue.ts
│   │   ├── useSetAtom.ts
│   │   ├── utils/
│   │   │   ├── useAtomCallback.ts
│   │   │   ├── useHydrateAtoms.ts
│   │   │   ├── useReducerAtom.ts
│   │   │   └── useResetAtom.ts
│   │   └── utils.ts
│   ├── react.ts
│   ├── types.d.ts
│   ├── utils.ts
│   ├── vanilla/
│   │   ├── atom.ts
│   │   ├── internals.ts
│   │   ├── store.ts
│   │   ├── typeUtils.ts
│   │   ├── utils/
│   │   │   ├── atomFamily.ts
│   │   │   ├── atomWithDefault.ts
│   │   │   ├── atomWithLazy.ts
│   │   │   ├── atomWithObservable.ts
│   │   │   ├── atomWithReducer.ts
│   │   │   ├── atomWithRefresh.ts
│   │   │   ├── atomWithReset.ts
│   │   │   ├── atomWithStorage.ts
│   │   │   ├── constants.ts
│   │   │   ├── freezeAtom.ts
│   │   │   ├── loadable.ts
│   │   │   ├── selectAtom.ts
│   │   │   ├── splitAtom.ts
│   │   │   └── unwrap.ts
│   │   └── utils.ts
│   └── vanilla.ts
├── tests/
│   ├── babel/
│   │   ├── plugin-debug-label.test.ts
│   │   ├── plugin-react-refresh.test.ts
│   │   └── preset.test.ts
│   ├── react/
│   │   ├── abortable.test.tsx
│   │   ├── async.test.tsx
│   │   ├── async2.test.tsx
│   │   ├── basic.test.tsx
│   │   ├── dependency.test.tsx
│   │   ├── error.test.tsx
│   │   ├── items.test.tsx
│   │   ├── onmount.test.tsx
│   │   ├── optimization.test.tsx
│   │   ├── provider.test.tsx
│   │   ├── transition.test.tsx
│   │   ├── types.test.tsx
│   │   ├── useAtomValue.test.tsx
│   │   ├── useSetAtom.test.tsx
│   │   ├── utils/
│   │   │   ├── types.test.tsx
│   │   │   ├── useAtomCallback.test.tsx
│   │   │   ├── useHydrateAtoms.test.tsx
│   │   │   ├── useReducerAtom.test.tsx
│   │   │   └── useResetAtom.test.tsx
│   │   └── vanilla-utils/
│   │       ├── atomFamily.test.tsx
│   │       ├── atomWithDefault.test.tsx
│   │       ├── atomWithObservable.test.tsx
│   │       ├── atomWithReducer.test.tsx
│   │       ├── atomWithRefresh.test.tsx
│   │       ├── atomWithStorage.test.tsx
│   │       ├── freezeAtom.test.tsx
│   │       ├── loadable.test.tsx
│   │       ├── selectAtom.test.tsx
│   │       └── splitAtom.test.tsx
│   ├── setup.ts
│   ├── test-utils.ts
│   └── vanilla/
│       ├── basic.test.tsx
│       ├── dependency.test.tsx
│       ├── derive.test.tsx
│       ├── effect.test.ts
│       ├── internals.test.tsx
│       ├── memoryleaks.test.ts
│       ├── store.test.tsx
│       ├── storedev.test.tsx
│       ├── types.test.tsx
│       └── utils/
│           ├── atomFamily.test.ts
│           ├── atomWithDefault.test.ts
│           ├── atomWithLazy.test.ts
│           ├── atomWithRefresh.test.ts
│           ├── atomWithReset.test.ts
│           ├── loadable.test.ts
│           ├── types.test.tsx
│           └── unwrap.test.ts
├── tsconfig.json
├── vitest.config.mts
└── website/
    ├── .babelrc
    ├── .gitignore
    ├── README.md
    ├── api/
    │   └── contact.js
    ├── gatsby-browser.js
    ├── gatsby-config.js
    ├── gatsby-node.js
    ├── gatsby-shared.js
    ├── gatsby-ssr.js
    ├── jsconfig.json
    ├── package.json
    ├── postcss.config.js
    ├── reach-router.js
    ├── src/
    │   ├── api/
    │   │   └── contact.js
    │   ├── atoms/
    │   │   └── index.js
    │   ├── components/
    │   │   ├── button.js
    │   │   ├── client-only.js
    │   │   ├── code-sandbox.js
    │   │   ├── code.js
    │   │   ├── core-demo.js
    │   │   ├── credits.js
    │   │   ├── docs.js
    │   │   ├── extensions-demo.js
    │   │   ├── external-link.js
    │   │   ├── footer.js
    │   │   ├── headline.js
    │   │   ├── icon.js
    │   │   ├── inline-code.js
    │   │   ├── intro.js
    │   │   ├── jotai.js
    │   │   ├── layout.js
    │   │   ├── logo-cloud.js
    │   │   ├── logo.js
    │   │   ├── main.js
    │   │   ├── mdx.js
    │   │   ├── menu.js
    │   │   ├── meta.js
    │   │   ├── modal.js
    │   │   ├── search-button.js
    │   │   ├── search-modal.js
    │   │   ├── shelf.js
    │   │   ├── sidebar.js
    │   │   ├── stackblitz.js
    │   │   ├── support-modal.js
    │   │   ├── support.js
    │   │   ├── tabs.js
    │   │   ├── toc.js
    │   │   ├── toggle.js
    │   │   ├── utilities-demo.js
    │   │   └── wrapper.js
    │   ├── hooks/
    │   │   └── index.js
    │   ├── pages/
    │   │   ├── 404.js
    │   │   ├── docs/
    │   │   │   └── {Mdx.slug}.js
    │   │   └── index.js
    │   ├── styles/
    │   │   ├── base.css
    │   │   ├── components.css
    │   │   ├── fonts.css
    │   │   ├── index.css
    │   │   ├── layout.css
    │   │   ├── pmndrs.css
    │   │   └── utilities.css
    │   └── utils/
    │       └── index.js
    ├── static/
    │   └── robots.txt
    ├── tailwind.config.js
    └── vercel.json
Download .txt
SYMBOL INDEX (258 symbols across 64 files)

FILE: examples/hacker_news/src/App.tsx
  type PostData (line 6) | type PostData = {
  function Id (line 30) | function Id() {
  function Next (line 36) | function Next() {
  function PostTitle (line 47) | function PostTitle() {
  function App (line 60) | function App() {

FILE: examples/mega-form/src/App.tsx
  function App (line 153) | function App() {

FILE: examples/starter/src/index.tsx
  function App (line 28) | function App() {

FILE: examples/todos/src/App.tsx
  type Todo (line 8) | type Todo = {
  type RemoveFn (line 24) | type RemoveFn = (item: PrimitiveAtom<Todo>) => void
  type TodoItemProps (line 25) | type TodoItemProps = {
  type FilteredType (line 59) | type FilteredType = {
  function App (line 98) | function App() {

FILE: examples/todos_with_atomFamily/src/App.tsx
  type Param (line 9) | type Param = { id: string; title?: string }
  type Action (line 102) | type Action =
  function App (line 155) | function App() {

FILE: rollup.config.mjs
  function external (line 23) | function external(id) {
  function getBabelOptions (line 29) | function getBabelOptions(targets) {
  function getEsbuild (line 38) | function getEsbuild(env = 'development') {
  function createDeclarationConfig (line 47) | function createDeclarationConfig(input, output) {
  function createESMConfig (line 64) | function createESMConfig(input, output, clientOnly) {
  function createCommonJSConfig (line 90) | function createCommonJSConfig(input, output, clientOnly) {
  function createUMDConfig (line 109) | function createUMDConfig(input, output, env, clientOnly) {
  function createSystemConfig (line 148) | function createSystemConfig(input, output, env, clientOnly) {

FILE: src/babel/plugin-debug-label.ts
  function debugLabelPlugin (line 10) | function debugLabelPlugin(

FILE: src/babel/plugin-react-refresh.ts
  function reactRefreshPlugin (line 10) | function reactRefreshPlugin(

FILE: src/babel/preset.ts
  function jotaiPreset (line 7) | function jotaiPreset(

FILE: src/babel/utils.ts
  type PluginOptions (line 3) | interface PluginOptions {
  function isAtom (line 7) | function isAtom(

FILE: src/react/Provider.ts
  type Store (line 5) | type Store = ReturnType<typeof createStore>
  type StoreContextType (line 7) | type StoreContextType = ReturnType<typeof createContext<Store | undefined>>
  type Options (line 12) | type Options = {
  function useStore (line 16) | function useStore(options?: Options): Store {
  function Provider (line 21) | function Provider({

FILE: src/react/useAtom.ts
  type SetAtom (line 13) | type SetAtom<Args extends unknown[], Result> = (...args: Args) => Result
  type Options (line 15) | type Options = Parameters<typeof useAtomValue>[1]
  function useAtom (line 47) | function useAtom<Value, Args extends unknown[], Result>(

FILE: src/react/useAtomValue.ts
  type Store (line 6) | type Store = ReturnType<typeof useStore>
  type Options (line 104) | type Options = Parameters<typeof useStore>[0] & {
  function useAtomValue (line 119) | function useAtomValue<Value>(atom: Atom<Value>, options?: Options) {

FILE: src/react/useSetAtom.ts
  type SetAtom (line 9) | type SetAtom<Args extends unknown[], Result> = (...args: Args) => Result
  type Options (line 10) | type Options = Parameters<typeof useStore>[0]
  function useSetAtom (line 24) | function useSetAtom<Value, Args extends unknown[], Result>(

FILE: src/react/utils/useAtomCallback.ts
  type Options (line 6) | type Options = Parameters<typeof useSetAtom>[1]
  function useAtomCallback (line 8) | function useAtomCallback<Result, Args extends unknown[]>(

FILE: src/react/utils/useHydrateAtoms.ts
  type Store (line 4) | type Store = ReturnType<typeof useStore>
  type Options (line 5) | type Options = Parameters<typeof useStore>[0] & {
  type AnyWritableAtom (line 8) | type AnyWritableAtom = WritableAtom<any, any[], any>
  type InferAtomTuples (line 10) | type InferAtomTuples<T> = {
  type INTERNAL_InferAtomTuples (line 22) | type INTERNAL_InferAtomTuples<T> = InferAtomTuples<T>
  function useHydrateAtoms (line 39) | function useHydrateAtoms<

FILE: src/react/utils/useReducerAtom.ts
  type Options (line 5) | type Options = Parameters<typeof useAtom>[1]
  function useReducerAtom (line 27) | function useReducerAtom<Value, Action>(

FILE: src/react/utils/useResetAtom.ts
  type Options (line 6) | type Options = Parameters<typeof useSetAtom>[1]
  function useResetAtom (line 8) | function useResetAtom<T>(

FILE: src/types.d.ts
  type ImportMeta (line 1) | interface ImportMeta {

FILE: src/vanilla/atom.ts
  type Getter (line 3) | type Getter = <Value>(atom: Atom<Value>) => Value
  type Setter (line 5) | type Setter = <Value, Args extends unknown[], Result>(
  type SetAtom (line 10) | type SetAtom<Args extends unknown[], Result> = <A extends Args>(
  type Read (line 17) | type Read<Value, SetSelf = never> = (
  type Write (line 22) | type Write<Args extends unknown[], Result> = (
  type WithInitialValue (line 30) | type WithInitialValue<Value> = {
  type OnUnmount (line 34) | type OnUnmount = () => void
  type OnMount (line 36) | type OnMount<Args extends unknown[], Result> = <
  type Atom (line 42) | interface Atom<Value> {
  type WritableAtom (line 58) | interface WritableAtom<
  type SetStateAction (line 68) | type SetStateAction<Value> = Value | ((prev: Value) => Value)
  type PrimitiveAtom (line 70) | type PrimitiveAtom<Value> = WritableAtom<
  function atom (line 102) | function atom<Value, Args extends unknown[], Result>(
  function defaultRead (line 127) | function defaultRead<Value>(this: Atom<Value>, get: Getter) {
  function defaultWrite (line 131) | function defaultWrite<Value>(

FILE: src/vanilla/internals.ts
  type AnyValue (line 6) | type AnyValue = unknown
  type AnyError (line 7) | type AnyError = unknown
  type AnyAtom (line 8) | type AnyAtom = Atom<AnyValue>
  type AnyWritableAtom (line 9) | type AnyWritableAtom = WritableAtom<AnyValue, unknown[], unknown>
  type OnUnmount (line 10) | type OnUnmount = () => void
  type Getter (line 11) | type Getter = Parameters<AnyAtom['read']>[0]
  type Setter (line 12) | type Setter = Parameters<AnyWritableAtom['write']>[1]
  type EpochNumber (line 13) | type EpochNumber = number
  type AtomState (line 22) | type AtomState<Value = AnyValue> = {
  type Mounted (line 49) | type Mounted = {
  type WeakMapLike (line 60) | type WeakMapLike<K extends object, V> = {
  type SetLike (line 67) | type SetLike<T> = {
  type AtomStateMap (line 77) | type AtomStateMap = WeakMapLike<AnyAtom, AtomState>
  type MountedMap (line 78) | type MountedMap = WeakMapLike<AnyAtom, Mounted>
  type InvalidatedAtoms (line 79) | type InvalidatedAtoms = WeakMapLike<AnyAtom, EpochNumber>
  type ChangedAtoms (line 80) | type ChangedAtoms = SetLike<AnyAtom>
  type Callbacks (line 81) | type Callbacks = SetLike<() => void>
  type AtomRead (line 83) | type AtomRead = <Value>(
  type AtomWrite (line 88) | type AtomWrite = <Value, Args extends unknown[], Result>(
  type AtomOnInit (line 93) | type AtomOnInit = <Value>(store: Store, atom: Atom<Value>) => void
  type AtomOnMount (line 94) | type AtomOnMount = <Value, Args extends unknown[], Result>(
  type EnsureAtomState (line 100) | type EnsureAtomState = <Value>(
  type FlushCallbacks (line 104) | type FlushCallbacks = (store: Store) => void
  type RecomputeInvalidatedAtoms (line 105) | type RecomputeInvalidatedAtoms = (store: Store) => void
  type ReadAtomState (line 106) | type ReadAtomState = <Value>(
  type InvalidateDependents (line 110) | type InvalidateDependents = (store: Store, atom: AnyAtom) => void
  type WriteAtomState (line 111) | type WriteAtomState = <Value, Args extends unknown[], Result>(
  type MountDependencies (line 116) | type MountDependencies = (store: Store, atom: AnyAtom) => void
  type MountAtom (line 117) | type MountAtom = <Value>(store: Store, atom: Atom<Value>) => Mounted
  type UnmountAtom (line 118) | type UnmountAtom = <Value>(
  type SetAtomStateValueOrPromise (line 122) | type SetAtomStateValueOrPromise = <Value>(
  type StoreGet (line 127) | type StoreGet = <Value>(store: Store, atom: Atom<Value>) => Value
  type StoreSet (line 128) | type StoreSet = <Value, Args extends unknown[], Result>(
  type StoreSub (line 133) | type StoreSub = (
  type EnhanceBuildingBlocks (line 138) | type EnhanceBuildingBlocks = (
  type AbortHandlersMap (line 141) | type AbortHandlersMap = WeakMapLike<PromiseLike<unknown>, Set<() => void>>
  type RegisterAbortHandler (line 142) | type RegisterAbortHandler = <T>(
  type AbortPromise (line 147) | type AbortPromise = <T>(store: Store, promise: PromiseLike<T>) => void
  type Store (line 149) | type Store = {
  type BuildingBlocks (line 158) | type BuildingBlocks = [
  function hasInitialValue (line 224) | function hasInitialValue<T extends Atom<AnyValue>>(
  function isActuallyWritableAtom (line 230) | function isActuallyWritableAtom(atom: AnyAtom): atom is AnyWritableAtom {
  function isAtomStateInitialized (line 234) | function isAtomStateInitialized<Value>(atomState: AtomState<Value>): boo...
  function returnAtomValue (line 238) | function returnAtomValue<Value>(atomState: AtomState<Value>): Value {
  function isPromiseLike (line 248) | function isPromiseLike(p: unknown): p is PromiseLike<unknown> {
  function addPendingPromiseToDependency (line 252) | function addPendingPromiseToDependency(
  function getMountedOrPendingDependents (line 264) | function getMountedOrPendingDependents(
  type StoreHook (line 283) | type StoreHook = {
  type StoreHookForAtoms (line 288) | type StoreHookForAtoms = {
  type StoreHooks (line 295) | type StoreHooks = {
  function initializeStoreHooks (line 348) | function initializeStoreHooks(storeHooks: StoreHooks): Required<StoreHoo...
  method signal (line 598) | get signal() {
  method setSelf (line 604) | get setSelf() {
  function getBuildingBlocks (line 999) | function getBuildingBlocks(store: Store): Readonly<BuildingBlocks> {
  function buildStore (line 1008) | function buildStore(...buildArgs: Partial<BuildingBlocks>): Store {

FILE: src/vanilla/store.ts
  type Store (line 4) | type Store = INTERNAL_Store
  function INTERNAL_overrideCreateStore (line 8) | function INTERNAL_overrideCreateStore(
  function createStore (line 14) | function createStore(): Store {
  function getDefaultStore (line 23) | function getDefaultStore(): Store {

FILE: src/vanilla/typeUtils.ts
  type Getter (line 3) | type Getter = Parameters<Atom<unknown>['read']>[0]
  type Setter (line 4) | type Setter = Parameters<
  type ExtractAtomValue (line 8) | type ExtractAtomValue<AtomType> =
  type ExtractAtomArgs (line 11) | type ExtractAtomArgs<AtomType> =
  type ExtractAtomResult (line 16) | type ExtractAtomResult<AtomType> =
  type SetStateAction (line 21) | type SetStateAction<Value> = ExtractAtomArgs<PrimitiveAtom<Value>>[0]

FILE: src/vanilla/utils/atomFamily.ts
  type CreatedAt (line 6) | type CreatedAt = number
  type ShouldRemove (line 7) | type ShouldRemove<Param> = (createdAt: CreatedAt, param: Param) => boolean
  type Cleanup (line 8) | type Cleanup = () => void
  type Callback (line 9) | type Callback<Param, AtomType> = (event: {
  type AtomFamily (line 30) | interface AtomFamily<Param, AtomType> {
  function atomFamily (line 64) | function atomFamily<Param, AtomType extends Atom<unknown>>(

FILE: src/vanilla/utils/atomWithDefault.ts
  type Read (line 5) | type Read<Value, Args extends unknown[], Result> = WritableAtom<
  type DefaultSetStateAction (line 11) | type DefaultSetStateAction<Value> =
  function atomWithDefault (line 16) | function atomWithDefault<Value>(

FILE: src/vanilla/utils/atomWithLazy.ts
  function atomWithLazy (line 4) | function atomWithLazy<Value>(

FILE: src/vanilla/utils/atomWithObservable.ts
  type Timeout (line 7) | type Timeout = ReturnType<typeof setTimeout>
  type AnyError (line 8) | type AnyError = unknown
  type Subscription (line 10) | type Subscription = {
  type Observer (line 14) | type Observer<T> = {
  type SubscribableObservable (line 20) | type SubscribableObservable<T> =
  type SymbolObservable (line 33) | type SymbolObservable<T> = {
  type ObservableLike (line 37) | type ObservableLike<T> = SubscribableObservable<T> | SymbolObservable<T>
  type SubjectLike (line 39) | type SubjectLike<T> = ObservableLike<T> & Observer<T>
  type Options (line 41) | type Options<Data> = {
  type OptionsWithInitialValue (line 46) | type OptionsWithInitialValue<Data> = {
  function atomWithObservable (line 71) | function atomWithObservable<Data>(

FILE: src/vanilla/utils/atomWithReducer.ts
  function atomWithReducer (line 14) | function atomWithReducer<Value, Action>(

FILE: src/vanilla/utils/atomWithRefresh.ts
  type Read (line 4) | type Read<Value, Args extends unknown[], Result> = WritableAtom<
  type Write (line 9) | type Write<Value, Args extends unknown[], Result> = WritableAtom<
  function atomWithRefresh (line 24) | function atomWithRefresh<Value, Args extends unknown[], Result>(

FILE: src/vanilla/utils/atomWithReset.ts
  type SetStateActionWithReset (line 5) | type SetStateActionWithReset<Value> =
  type WithInitialValue (line 12) | type WithInitialValue<Value> = {
  function atomWithReset (line 16) | function atomWithReset<Value>(

FILE: src/vanilla/utils/atomWithStorage.ts
  type Unsubscribe (line 8) | type Unsubscribe = () => void
  type Subscribe (line 10) | type Subscribe<Value> = (
  type StringSubscribe (line 16) | type StringSubscribe = (
  type SetStateActionWithReset (line 21) | type SetStateActionWithReset<Value> =
  type AsyncStorage (line 26) | interface AsyncStorage<Value> {
  type SyncStorage (line 33) | interface SyncStorage<Value> {
  type AsyncStringStorage (line 40) | interface AsyncStringStorage {
  type SyncStringStorage (line 47) | interface SyncStringStorage {
  function withStorageValidator (line 61) | function withStorageValidator<Value>(
  type JsonStorageOptions (line 85) | type JsonStorageOptions = {
  function createJSONStorage (line 102) | function createJSONStorage<Value>(
  function atomWithStorage (line 218) | function atomWithStorage<Value>(

FILE: src/vanilla/utils/constants.ts
  constant RESET (line 1) | const RESET: unique symbol = Symbol(

FILE: src/vanilla/utils/freezeAtom.ts
  function freezeAtom (line 21) | function freezeAtom(
  function freezeAtomCreator (line 56) | function freezeAtomCreator<

FILE: src/vanilla/utils/loadable.ts
  type Loadable (line 9) | type Loadable<Value> =
  function loadable (line 38) | function loadable<Value>(anAtom: Atom<Value>): Atom<Loadable<Value>> {

FILE: src/vanilla/utils/selectAtom.ts
  function selectAtom (line 24) | function selectAtom<Value, Slice>(

FILE: src/vanilla/utils/splitAtom.ts
  type SplitAtomAction (line 28) | type SplitAtomAction<Item> =
  function splitAtom (line 51) | function splitAtom<Item, Key>(

FILE: src/vanilla/utils/unwrap.ts
  function unwrap (line 35) | function unwrap<Value, Args extends unknown[], Result, PendingValue>(

FILE: tests/react/async2.test.tsx
  function TestComponent (line 182) | function TestComponent() {

FILE: tests/react/basic.test.tsx
  constant IS_REACT18 (line 25) | const IS_REACT18 = /^18\./.test(reactVersion)
  type Props (line 168) | type Props = { countAtom: typeof count1Atom; name: string }

FILE: tests/react/error.test.tsx
  class ErrorBoundary (line 34) | class ErrorBoundary extends Component<
    method constructor (line 38) | constructor(props: { message?: string; children: ReactNode }) {
    method getDerivedStateFromError (line 42) | static getDerivedStateFromError(error: Error) {
    method render (line 45) | render() {

FILE: tests/react/items.test.tsx
  type Item (line 9) | type Item = {
  type Item (line 90) | type Item = {
  type ItemAtoms (line 94) | type ItemAtoms = PrimitiveAtom<Item>[]
  type Update (line 95) | type Update = (prev: ItemAtoms) => ItemAtoms

FILE: tests/react/types.test.tsx
  function Component (line 6) | function Component() {
  function Component (line 53) | function Component() {
  function Component (line 90) | function Component() {
  function Component (line 110) | function Component() {
  function Component (line 134) | function Component() {

FILE: tests/react/useAtomValue.test.tsx
  class ErrorBoundary (line 65) | class ErrorBoundary extends Component<
    method constructor (line 69) | constructor(props: { children: ReactNode }) {
    method getDerivedStateFromError (line 75) | static getDerivedStateFromError(error: Error) {
    method render (line 79) | render() {

FILE: tests/react/useSetAtom.test.tsx
  function TestComponent (line 112) | function TestComponent() {

FILE: tests/react/utils/types.test.tsx
  function Component (line 6) | function Component() {

FILE: tests/react/utils/useHydrateAtoms.test.tsx
  type AnyWritableAtom (line 379) | type AnyWritableAtom = WritableAtom<unknown, unknown[], unknown>

FILE: tests/react/vanilla-utils/atomWithObservable.test.tsx
  class ErrorBoundary (line 50) | class ErrorBoundary extends Component<
    method getDerivedStateFromError (line 58) | static getDerivedStateFromError(error: Error) {
    method render (line 62) | render() {
    method constructor (line 591) | constructor(props: { message?: string; children: ReactNode }) {
    method getDerivedStateFromError (line 595) | static getDerivedStateFromError() {
    method render (line 598) | render() {
  class ErrorBoundary (line 587) | class ErrorBoundary extends Component<
    method getDerivedStateFromError (line 58) | static getDerivedStateFromError(error: Error) {
    method render (line 62) | render() {
    method constructor (line 591) | constructor(props: { message?: string; children: ReactNode }) {
    method getDerivedStateFromError (line 595) | static getDerivedStateFromError() {
    method render (line 598) | render() {

FILE: tests/react/vanilla-utils/atomWithStorage.test.tsx
  method get (line 433) | get() {
  method get (line 438) | get() {
  method get (line 452) | get() {
  method get (line 457) | get() {
  method get (line 624) | get() {
  method subscribe (line 888) | subscribe(_key, callback) {
  method getItem (line 942) | getItem(_key: string, _initialValue: number) {
  method setItem (line 950) | async setItem(_key, newValue) {
  method removeItem (line 953) | async removeItem() {}

FILE: tests/react/vanilla-utils/loadable.test.tsx
  type LoadableComponentProps (line 293) | type LoadableComponentProps = {

FILE: tests/react/vanilla-utils/splitAtom.test.tsx
  type TodoItem (line 10) | type TodoItem = { task: string; checked?: boolean }
  function useCachedAtoms (line 408) | function useCachedAtoms<T>(atoms: T[]) {
  type NumItemProps (line 414) | type NumItemProps = { atom: Atom<number> }
  function Filter (line 424) | function Filter() {
  function App (line 462) | function App() {
  function App (line 494) | function App() {

FILE: tests/test-utils.ts
  function sleep (line 3) | function sleep(ms: number): Promise<void> {
  function useCommitCount (line 7) | function useCommitCount(): number {

FILE: tests/vanilla/derive.test.tsx
  type AtomStateMapType (line 9) | type AtomStateMapType = ReturnType<typeof INTERNAL_getBuildingBlocks>[0]
  function makeStores (line 137) | function makeStores() {

FILE: tests/vanilla/effect.test.ts
  type Cleanup (line 17) | type Cleanup = () => void
  type Effect (line 18) | type Effect = (get: Getter, set: Setter) => Cleanup | void
  type Ref (line 19) | type Ref = {
  function syncEffect (line 26) | function syncEffect(effect: Effect): Atom<void> {
  function ensureSyncEffectChannel (line 95) | function ensureSyncEffectChannel(store: any) {
  type Ref (line 225) | type Ref = {
  function runEffect (line 254) | function runEffect() {

FILE: tests/vanilla/internals.test.tsx
  function storeGet (line 73) | function storeGet() {
  function isSparse (line 239) | function isSparse(arr: ReadonlyArray<unknown>) {
  function isBuildingBlocks (line 243) | function isBuildingBlocks(blocks: ReadonlyArray<unknown> | undefined) {

FILE: tests/vanilla/store.test.tsx
  type DevStore (line 25) | type DevStore = {
  type AtomStateMapType (line 53) | type AtomStateMapType = ReturnType<typeof INTERNAL_getBuildingBlocks>[0]
  function getMaxDepth (line 1028) | function getMaxDepth() {
  type Store (line 1148) | type Store = ReturnType<typeof createStore>
  function testInStore (line 1149) | function testInStore(store: Store) {

FILE: tests/vanilla/storedev.test.tsx
  type DevStore (line 13) | type DevStore = {

FILE: tests/vanilla/types.test.tsx
  type ReadWriteAtom (line 64) | type ReadWriteAtom = typeof readWriteAtom

FILE: tests/vanilla/utils/atomFamily.test.ts
  type Event (line 65) | type Event = { type: 'CREATE' | 'REMOVE'; param: number; atom: Atom<numb...

FILE: website/api/contact.js
  function handler (line 5) | async function handler(request, response) {

FILE: website/gatsby-config.js
  constant DOCS_QUERY (line 11) | const DOCS_QUERY = `

FILE: website/src/api/contact.js
  function handler (line 5) | async function handler(request, response) {

FILE: website/src/pages/404.js
  function NotFoundPage (line 4) | function NotFoundPage() {

FILE: website/src/pages/docs/{Mdx.slug}.js
  function DocsPage (line 6) | function DocsPage({ data }) {

FILE: website/src/pages/index.js
  function HomePage (line 13) | function HomePage() {
Condensed preview — 326 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,043K chars).
[
  {
    "path": ".codesandbox/ci.json",
    "chars": 291,
    "preview": "{\n  \"packages\": [\"dist\"],\n  \"sandboxes\": [\n    \"new\",\n    \"react-typescript-react-ts\",\n    \"simple-react-browserify-x9yn"
  },
  {
    "path": ".github/DISCUSSION_TEMPLATE/bug-report.yml",
    "chars": 588,
    "preview": "labels: ['bug']\nbody:\n  - type: markdown\n    attributes:\n      value: If you don't have a reproduction link, please choo"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 772,
    "preview": "# These are supported funding model platforms\n\ngithub: [dai-shi] # Replace with up to 4 GitHub Sponsors-enabled username"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 171,
    "preview": "---\nname: Assigned issue\nabout: This is to create a new issue that already has an assignee. Please open a new discussion"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 463,
    "preview": "blank_issues_enabled: false\ncontact_links:\n  - name: Bug Reports\n    url: https://github.com/pmndrs/jotai/discussions/ne"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 137,
    "preview": "## Related Bug Reports or Discussions\n\nFixes #\n\n## Summary\n\n## Check List\n\n- [ ] `pnpm run fix` for formatting and linti"
  },
  {
    "path": ".github/workflows/compressed-size.yml",
    "chars": 570,
    "preview": "name: Compressed Size\n\non: [pull_request]\n\njobs:\n  compressed_size:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: "
  },
  {
    "path": ".github/workflows/ecosystem-ci.yml",
    "chars": 1809,
    "preview": "name: Ecosystem CI\n\non:\n  issue_comment:\n    types: [created]\n\njobs:\n  trigger:\n    runs-on: ubuntu-latest\n    if: ${{ g"
  },
  {
    "path": ".github/workflows/livecodes-post-comment.yml",
    "chars": 496,
    "preview": "name: LiveCodes Post Comment\n\non:\n  workflow_run:\n    workflows: [LiveCodes Preview]\n    types:\n      - completed\n\njobs:"
  },
  {
    "path": ".github/workflows/livecodes-preview.yml",
    "chars": 694,
    "preview": "name: LiveCodes Preview\n\non: [pull_request]\n\njobs:\n  build_and_prepare:\n    runs-on: ubuntu-latest\n    steps:\n      - us"
  },
  {
    "path": ".github/workflows/preview-release.yml",
    "chars": 568,
    "preview": "name: Preview Release\n\non: [push, pull_request]\n\njobs:\n  preview_release:\n    runs-on: ubuntu-latest\n    steps:\n      - "
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 638,
    "preview": "name: Publish\n\non:\n  release:\n    types: [published]\n\npermissions:\n  id-token: write\n  contents: read\n\njobs:\n  publish:\n"
  },
  {
    "path": ".github/workflows/stale-discussions.yml",
    "chars": 509,
    "preview": "name: Close Stale Discussions\n\non:\n  schedule:\n    - cron: '0 0 * * *' # Runs every day at midnight UTC\n  workflow_dispa"
  },
  {
    "path": ".github/workflows/test-multiple-builds.yml",
    "chars": 3841,
    "preview": "name: Test Multiple Builds\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  t"
  },
  {
    "path": ".github/workflows/test-multiple-versions.yml",
    "chars": 1801,
    "preview": "name: Test Multiple Versions\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n "
  },
  {
    "path": ".github/workflows/test-old-typescript.yml",
    "chars": 5810,
    "preview": "name: Test Old TypeScript\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  te"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 698,
    "preview": "name: Test\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  test:\n    runs-on"
  },
  {
    "path": ".gitignore",
    "chars": 437,
    "preview": "# dependencies\nnode_modules\n.pnp\n.pnp.js\n\n# testing\ncoverage\n\n# development\n.devcontainer\n.vscode\n\n# production\ndist\nbui"
  },
  {
    "path": ".livecodes/react.json",
    "chars": 1570,
    "preview": "{\n  \"title\": \"React demo\",\n  \"activeEditor\": \"script\",\n  \"markup\": {\n    \"language\": \"html\",\n    \"content\": \"<div id=\\\"r"
  },
  {
    "path": ".prettierignore",
    "chars": 20,
    "preview": "dist\npnpm-lock.yaml\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3930,
    "preview": "# Contributing\n\n## General Guideline\n\n### Reporting Issues\n\nIf you have found what you think is a bug, please [start a d"
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2020 Poimandres\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "README.md",
    "chars": 5541,
    "preview": "<br>\n\n![Jotai (light mode)](./img/jotai-header-light.png#gh-light-mode-only)\n![Jotai (dark mode)](./img/jotai-header-dar"
  },
  {
    "path": "babel.config.mjs",
    "chars": 631,
    "preview": "export default (api, targets) => {\n  // https://babeljs.io/docs/en/config-files#config-function-api\n  const isTestEnv = "
  },
  {
    "path": "benchmarks/.gitignore",
    "chars": 16,
    "preview": "/*.json\n/*.html\n"
  },
  {
    "path": "benchmarks/simple-read.ts",
    "chars": 1247,
    "preview": "#!/usr/bin/env npx tsx\n\n/// <reference types=\"node\" />\n\nimport path from 'node:path'\nimport { fileURLToPath } from 'node"
  },
  {
    "path": "benchmarks/simple-write.ts",
    "chars": 1264,
    "preview": "#!/usr/bin/env npx tsx\n\n/// <reference types=\"node\" />\n\nimport path from 'node:path'\nimport { fileURLToPath } from 'node"
  },
  {
    "path": "benchmarks/subscribe-write.ts",
    "chars": 1503,
    "preview": "#!/usr/bin/env npx tsx\n\n/// <reference types=\"node\" />\n\nimport path from 'node:path'\nimport { fileURLToPath } from 'node"
  },
  {
    "path": "docs/basics/comparison.mdx",
    "chars": 5767,
    "preview": "---\ntitle: Comparison\nnav: 7.02\n---\n\nJotai was born to solve extra re-render issues in React.\nAn extra re-render is when"
  },
  {
    "path": "docs/basics/concepts.mdx",
    "chars": 1634,
    "preview": "---\ntitle: Concepts\nnav: 7.01\n---\n\nJotai is a library that will make you return to the basics of React development & kee"
  },
  {
    "path": "docs/basics/functional-programming-and-jotai.mdx",
    "chars": 4473,
    "preview": "---\ntitle: Functional programming and Jotai\nnav: 7.04\n---\n\n### Unexpected similarities\n\nIf you look at getter functions "
  },
  {
    "path": "docs/basics/showcase.mdx",
    "chars": 2159,
    "preview": "---\ntitle: Showcase\nnav: 7.03\n---\n\n- Text Length example [![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-"
  },
  {
    "path": "docs/core/atom.mdx",
    "chars": 8623,
    "preview": "---\ntitle: atom\ndescription: This doc describes core `jotai` bundle.\nnav: 2.01\nkeywords: atom,primitive,derived,debug,la"
  },
  {
    "path": "docs/core/provider.mdx",
    "chars": 1664,
    "preview": "---\ntitle: Provider\ndescription: This doc describes core `jotai` bundle.\nnav: 2.04\nkeywords: provider,usestore,ssr\n---\n\n"
  },
  {
    "path": "docs/core/store.mdx",
    "chars": 848,
    "preview": "---\ntitle: Store\ndescription: This doc describes core `jotai` bundle.\nnav: 2.03\nkeywords: store,createstore,getdefaultst"
  },
  {
    "path": "docs/core/use-atom.mdx",
    "chars": 5592,
    "preview": "---\ntitle: useAtom\ndescription: This doc describes core `jotai` bundle.\nnav: 2.02\nkeywords: use,useatom,useatomvalue,use"
  },
  {
    "path": "docs/extensions/cache.mdx",
    "chars": 2633,
    "preview": "---\ntitle: Cache\ndescription: This doc describes cache extension.\nnav: 4.07\nkeywords: cache\n---\n\nJotai provides primitiv"
  },
  {
    "path": "docs/extensions/effect.mdx",
    "chars": 8340,
    "preview": "---\ntitle: Effect\ndescription: A Jōtai utility package for reactive side effects\nnav: 4.03\nkeywords: effect, atom effect"
  },
  {
    "path": "docs/extensions/immer.mdx",
    "chars": 3025,
    "preview": "---\ntitle: Immer\ndescription: This doc describes Immer extension.\nnav: 4.04\nkeywords: immer\n---\n\n### Install\n\nYou have t"
  },
  {
    "path": "docs/extensions/location.mdx",
    "chars": 4543,
    "preview": "---\ntitle: Location\ndescription: This doc describes window.location extension.\nnav: 4.06\nkeywords: location,hash\n---\n\nTo"
  },
  {
    "path": "docs/extensions/optics.mdx",
    "chars": 2017,
    "preview": "---\ntitle: Optics\ndescription: This doc describes Optics-ts extension.\nnav: 4.09\nkeywords: optics\n---\n\n### Install\n\nYou "
  },
  {
    "path": "docs/extensions/query.mdx",
    "chars": 14924,
    "preview": "---\ntitle: Query\ndescription: This doc describes TanStack Query extension.\nnav: 4.02\nkeywords: tanstack,query\n---\n\n[TanS"
  },
  {
    "path": "docs/extensions/redux.mdx",
    "chars": 1260,
    "preview": "---\ntitle: Redux\ndescription: This doc describes Redux extension.\nnav: 4.98\nkeywords: redux\npublished: false\n---\n\nJotai'"
  },
  {
    "path": "docs/extensions/relay.mdx",
    "chars": 2365,
    "preview": "---\ntitle: Relay\ndescription: This doc describes Relay extension.\nnav: 4.98\nkeywords: relay\npublished: false\n---\n\nYou ca"
  },
  {
    "path": "docs/extensions/scope.mdx",
    "chars": 3952,
    "preview": "---\ntitle: Scope\ndescription: This doc describes scope extension.\nnav: 4.08\nkeywords: scope\n---\n\nThere are a few librari"
  },
  {
    "path": "docs/extensions/trpc.mdx",
    "chars": 2137,
    "preview": "---\ntitle: tRPC\ndescription: This doc describes tRPC extension.\nnav: 4.01\nkeywords: rpc,trpc,typescript,t3\n---\n\nYou can "
  },
  {
    "path": "docs/extensions/urql.mdx",
    "chars": 8050,
    "preview": "---\ntitle: URQL\ndescription: This doc describes URQL extension.\nnav: 4.03\nkeywords: urql\n---\n\n[urql](https://formidable."
  },
  {
    "path": "docs/extensions/valtio.mdx",
    "chars": 2973,
    "preview": "---\ntitle: Valtio\ndescription: This doc describes Valtio extension.\nnav: 4.98\nkeywords: valtio,proxy\npublished: false\n--"
  },
  {
    "path": "docs/extensions/xstate.mdx",
    "chars": 3540,
    "preview": "---\ntitle: XState\ndescription: This doc describes XState extension.\nnav: 4.05\nkeywords: xstate,machine,atomwithmachine\n-"
  },
  {
    "path": "docs/extensions/zustand.mdx",
    "chars": 1190,
    "preview": "---\ntitle: Zustand\ndescription: This doc describes Zustand extension.\nnav: 4.98\nkeywords: zustand\npublished: false\n---\n\n"
  },
  {
    "path": "docs/guides/async.mdx",
    "chars": 3936,
    "preview": "---\ntitle: Async\ndescription: This doc describes about the behavior with async.\nnav: 8.99\nkeywords: async\npublished: fal"
  },
  {
    "path": "docs/guides/atoms-in-atom.mdx",
    "chars": 3878,
    "preview": "---\ntitle: Atoms in atom\nnav: 8.12\n---\n\n`atom()` creates an atom config, which is an object, but it doesn't hold a value"
  },
  {
    "path": "docs/guides/composing-atoms.mdx",
    "chars": 6502,
    "preview": "---\ntitle: Composing atoms\nnav: 8.11\n---\n\nThe `atom` function provided by library is very primitive,\nbut it's also so fl"
  },
  {
    "path": "docs/guides/core-internals.mdx",
    "chars": 6566,
    "preview": "---\ntitle: Core internals\ndescription: A simplified version of the core implementation\nnav: 8.10\n---\n\nThis guide is bene"
  },
  {
    "path": "docs/guides/debugging.mdx",
    "chars": 6857,
    "preview": "---\ntitle: Debugging\nnav: 8.07\nkeywords: debug,labels,devtools,freeze\n---\n\nIn basic apps, `console.log` can be our best "
  },
  {
    "path": "docs/guides/initialize-atom-on-render.mdx",
    "chars": 3888,
    "preview": "---\ntitle: Initializing state on render\ndescription: How to initialize atom state on initial render\nnav: 8.13\n---\n\nThere"
  },
  {
    "path": "docs/guides/migrating-to-v2-api.mdx",
    "chars": 6225,
    "preview": "---\ntitle: v2 API migration\ndescription: New \"Async\" API\nnav: 8.0\n---\n\nRFC: https://github.com/pmndrs/jotai/discussions/"
  },
  {
    "path": "docs/guides/nextjs.mdx",
    "chars": 3860,
    "preview": "---\ntitle: Next.js\ndescription: How to use Jotai with Next.js\nnav: 8.03\nkeywords: next,nextjs\n---\n\n### Hydration\n\nJotai "
  },
  {
    "path": "docs/guides/performance.mdx",
    "chars": 4084,
    "preview": "---\ntitle: Performance\ndescription: How to limit extra re-renders\nnav: 8.08\nkeywords: performance\n---\n\n**Note**: This gu"
  },
  {
    "path": "docs/guides/persistence.mdx",
    "chars": 5245,
    "preview": "---\ntitle: Persistence\ndescription: How to persist atoms\nnav: 8.14\n---\n\nJotai has an [atomWithStorage function in the ut"
  },
  {
    "path": "docs/guides/react-native.mdx",
    "chars": 1152,
    "preview": "---\ntitle: React Native\ndescription: Using Jotai in React Native\nnav: 8.06\nkeywords: native,ios,android\n---\n\nJotai atoms"
  },
  {
    "path": "docs/guides/remix.mdx",
    "chars": 256,
    "preview": "---\ntitle: Remix\ndescription: How to use Jotai with Remix\nnav: 8.05\nkeywords: remix\nstatus: draft\n---\n\n### Hydration\n\nJo"
  },
  {
    "path": "docs/guides/resettable.mdx",
    "chars": 2004,
    "preview": "---\ntitle: Resettable\ndescription: How to use resettable atoms\nnav: 8.99\npublished: false\n---\n\nThe Jotai core doesn't su"
  },
  {
    "path": "docs/guides/testing.mdx",
    "chars": 4166,
    "preview": "---\ntitle: Testing\ndescription: How to test your code using Jotai\nnav: 8.09\nkeywords: test,testing\n---\n\nWe echo the [gui"
  },
  {
    "path": "docs/guides/typescript.mdx",
    "chars": 3660,
    "preview": "---\ntitle: TypeScript\ndescription: How to use Jotai with TypeScript\nnav: 8.02\nkeywords: typescript,types\n---\n\n### Versio"
  },
  {
    "path": "docs/guides/using-store-outside-react.mdx",
    "chars": 1049,
    "preview": "---\ntitle: Using store outside React\ndescription: Using store outside React\nnav: 8.98\nkeywords: state, outside, react\npu"
  },
  {
    "path": "docs/guides/vite.mdx",
    "chars": 800,
    "preview": "---\ntitle: Vite\ndescription: How to use Jotai with Vite\nnav: 8.99\nkeywords: vite\npublished: false\n---\n\nYou can use the p"
  },
  {
    "path": "docs/guides/waku.mdx",
    "chars": 249,
    "preview": "---\ntitle: Waku\ndescription: How to use Jotai with Waku\nnav: 8.04\nkeywords: waku\nstatus: draft\n---\n\n### Hydration\n\nJotai"
  },
  {
    "path": "docs/index.mdx",
    "chars": 1723,
    "preview": "---\ntitle: Documentation\ndescription: Table of contents\nnav: 0\n---\n\nWelcome to the Jotai v2 documentation! Jotai's atomi"
  },
  {
    "path": "docs/recipes/atom-with-broadcast.mdx",
    "chars": 2157,
    "preview": "---\ntitle: atomWithBroadcast\nnav: 9.09\nkeywords: creators,broadcast\n---\n\n> `atomWithBroadcast` creates an atom. The atom"
  },
  {
    "path": "docs/recipes/atom-with-compare.mdx",
    "chars": 1685,
    "preview": "---\ntitle: atomWithCompare\nnav: 9.05\nkeywords: creators,compare\n---\n\n> `atomWithCompare` creates atom that triggers upda"
  },
  {
    "path": "docs/recipes/atom-with-debounce.mdx",
    "chars": 2974,
    "preview": "---\ntitle: atomWithDebounce\nnav: 9.10\nkeywords: creators,debounce\n---\n\n> `atomWithDebounce` helps with creating an atom "
  },
  {
    "path": "docs/recipes/atom-with-listeners.mdx",
    "chars": 2230,
    "preview": "---\ntitle: atomWithListeners\nnav: 9.08\nkeywords: creators,listeners\n---\n\n> `atomWithListeners` creates an atom and a hoo"
  },
  {
    "path": "docs/recipes/atom-with-refresh-and-default.mdx",
    "chars": 2323,
    "preview": "---\ntitle: atomWithRefreshAndDefault\nnav: 9.07\nkeywords: creators,refresh,default\n---\n\n> This is for another implementat"
  },
  {
    "path": "docs/recipes/atom-with-refresh.mdx",
    "chars": 199,
    "preview": "---\ntitle: atomWithRefresh\nnav: 9.06\nkeywords: creators,refresh\n---\n\n`atomWithRefresh` has been provided by `jotai/utils"
  },
  {
    "path": "docs/recipes/atom-with-toggle-and-storage.mdx",
    "chars": 1125,
    "preview": "---\ntitle: atomWithToggleAndStorage\nnav: 9.05\nkeywords: creators,storage\n---\n\n> `atomWithToggleAndStorage` is like `atom"
  },
  {
    "path": "docs/recipes/atom-with-toggle.mdx",
    "chars": 1370,
    "preview": "---\ntitle: atomWithToggle\nnav: 9.04\nkeywords: creators,toggle\n---\n\n> `atomWithToggle` creates a new atom with a boolean "
  },
  {
    "path": "docs/recipes/custom-useatom-hooks.mdx",
    "chars": 1896,
    "preview": "---\ntitle: Custom useAtom hooks\nnav: 9.02\nkeywords: custom,hook\n---\n\nThis page shows the ways of creating different util"
  },
  {
    "path": "docs/recipes/large-objects.mdx",
    "chars": 3646,
    "preview": "---\ntitle: Large objects\nnav: 9.01\nkeywords: large,object\n---\n\n> The examples and descriptions below are based on this ["
  },
  {
    "path": "docs/recipes/use-atom-effect.mdx",
    "chars": 2185,
    "preview": "---\ntitle: useAtomEffect\nnav: 9.03\nkeywords: effect, atom effect, side effect, side-effect, sideeffect, hook, useAtomEff"
  },
  {
    "path": "docs/recipes/use-reducer-atom.mdx",
    "chars": 1362,
    "preview": "---\ntitle: useReducerAtom\nnav: 9.11\nkeywords: reducer, hook, useReducerAtom\n---\n\n`useReducerAtom` is a custom hook to ap"
  },
  {
    "path": "docs/third-party/bunja.mdx",
    "chars": 6291,
    "preview": "---\ntitle: Bunja\ndescription: State Lifetime Manager\nnav: 5.03\nkeywords: scope,di,raii,lifetime\n---\n\n[Bunja](https://git"
  },
  {
    "path": "docs/third-party/derive.mdx",
    "chars": 4426,
    "preview": "---\ntitle: Derive\ndescription: This doc describes Derive extension.\nnav: 5.01\nkeywords: derive,derived,async,zalgo,suspe"
  },
  {
    "path": "docs/third-party/history.mdx",
    "chars": 2011,
    "preview": "---\ntitle: History\ndescription: A Jōtai utility package for state history\nnav: 4.04\nkeywords: history, undo, redo, track"
  },
  {
    "path": "docs/tools/babel.mdx",
    "chars": 2978,
    "preview": "---\ntitle: Babel\ndescription: This doc describes the `jotai-babel` package.\nnav: 6.02\nkeywords: babel,gatsby,fast,refres"
  },
  {
    "path": "docs/tools/devtools.mdx",
    "chars": 10684,
    "preview": "---\ntitle: Devtools\ndescription: This doc describes Devtools for Jotai.\nnav: 6.03\nkeywords: devtools,debug,snapshot\n---\n"
  },
  {
    "path": "docs/tools/swc.mdx",
    "chars": 2778,
    "preview": "---\ntitle: SWC\ndescription: This doc describes SWC plugins for Jotai.\nnav: 6.01\nkeywords: swc,next,nextjs,fast,refresh\n-"
  },
  {
    "path": "docs/utilities/async.mdx",
    "chars": 4007,
    "preview": "---\ntitle: Async\nnav: 3.03\nkeywords: load,loadable,observable\n---\n\nAll atoms support async behavior such as async read o"
  },
  {
    "path": "docs/utilities/callback.mdx",
    "chars": 1495,
    "preview": "---\ntitle: Callback\nnav: 3.99\nkeywords: callback\npublished: false\n---\n\n## useAtomCallback\n\nRef: https://github.com/pmndr"
  },
  {
    "path": "docs/utilities/family.mdx",
    "chars": 5575,
    "preview": "---\ntitle: Family\nnav: 3.5\nkeywords: family\n---\n\n## atomFamily\n\n:::caution Deprecated\n`atomFamily` is deprecated and wil"
  },
  {
    "path": "docs/utilities/lazy.mdx",
    "chars": 2372,
    "preview": "---\ntitle: Lazy\nnav: 3.03\nkeywords: lazy,initialize,init,loading\n---\n\nWhen defining primitive atoms, their initial value"
  },
  {
    "path": "docs/utilities/reducer.mdx",
    "chars": 602,
    "preview": "---\ntitle: Reducer\nnav: 3.99\nkeywords: reducer,action,dispatch\npublished: false\n---\n\n## atomWithReducer\n\nRef: https://gi"
  },
  {
    "path": "docs/utilities/resettable.mdx",
    "chars": 5245,
    "preview": "---\ntitle: Resettable\nnav: 3.04\nkeywords: reset,default\n---\n\n## atomWithReset\n\nRef: https://github.com/pmndrs/jotai/issu"
  },
  {
    "path": "docs/utilities/select.mdx",
    "chars": 2779,
    "preview": "---\ntitle: Select\nnav: 3.99\nkeywords: select\npublished: false\n---\n\n## selectAtom\n\n⚠️ Unlike its name, `selectAtom` is pr"
  },
  {
    "path": "docs/utilities/split.mdx",
    "chars": 3419,
    "preview": "---\ntitle: Split\nnav: 3.99\nkeywords: select\npublished: false\n---\n\n## splitAtom\n\nThe `splitAtom` utility is designed for "
  },
  {
    "path": "docs/utilities/ssr.mdx",
    "chars": 2685,
    "preview": "---\ntitle: SSR\nnav: 3.02\nkeywords: ssr,server,hydrate,hydration,next,nextjs,gatsby,remix,waku,framework\n---\n\n## useHydra"
  },
  {
    "path": "docs/utilities/storage.mdx",
    "chars": 8873,
    "preview": "---\ntitle: Storage\nnav: 3.01\nkeywords: storage,localstorage,sessionstorage,asyncstorage,persist,persistence\n---\n\n## atom"
  },
  {
    "path": "eslint.config.mjs",
    "chars": 2945,
    "preview": "import eslint from '@eslint/js'\nimport vitest from '@vitest/eslint-plugin'\nimport { defineConfig, globalIgnores } from '"
  },
  {
    "path": "examples/hacker_news/README.md",
    "chars": 676,
    "preview": "# Hacker News [![Open in StackBlitz](https://img.shields.io/badge/Open%20in-StackBlitz-blue?style=flat-square&logo=stack"
  },
  {
    "path": "examples/hacker_news/index.html",
    "chars": 366,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/hacker_news/package.json",
    "chars": 613,
    "preview": "{\n  \"name\": \"hacker_news\",\n  \"version\": \"2.0.0\",\n  \"description\": \"Demonstrate a news articles with jotai, hit next to s"
  },
  {
    "path": "examples/hacker_news/public/index.html",
    "chars": 1626,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta\n      name=\"viewport\"\n      content=\"wi"
  },
  {
    "path": "examples/hacker_news/src/App.tsx",
    "chars": 1599,
    "preview": "import { Suspense } from 'react'\nimport { a, useSpring } from '@react-spring/web'\nimport Parser from 'html-react-parser'"
  },
  {
    "path": "examples/hacker_news/src/index.tsx",
    "chars": 259,
    "preview": "import { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport './styles.css'\nimport App from '"
  },
  {
    "path": "examples/hacker_news/src/styles.css",
    "chars": 1195,
    "preview": "@import url('https://rsms.me/inter/inter.css');\n\n* {\n  box-sizing: border-box;\n  outline: none !important;\n}\n\nhtml,\nbody"
  },
  {
    "path": "examples/hacker_news/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/hacker_news/tsconfig.json",
    "chars": 544,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es2019\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDef"
  },
  {
    "path": "examples/hacker_news/vite.config.ts",
    "chars": 133,
    "preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n  plugins: ["
  },
  {
    "path": "examples/hello/README.md",
    "chars": 565,
    "preview": "# Hello [![Open in StackBlitz](https://img.shields.io/badge/Open%20in-StackBlitz-blue?style=flat-square&logo=stackblitz)"
  },
  {
    "path": "examples/hello/index.html",
    "chars": 521,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <"
  },
  {
    "path": "examples/hello/package.json",
    "chars": 519,
    "preview": "{\n  \"name\": \"hello\",\n  \"version\": \"2.0.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    "
  },
  {
    "path": "examples/hello/public/index.html",
    "chars": 597,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"%PUBLIC_URL%/favicon.i"
  },
  {
    "path": "examples/hello/src/App.tsx",
    "chars": 1728,
    "preview": "import { atom, useAtom } from 'jotai'\n// @ts-ignore\nimport PrismCode from 'react-prism'\nimport 'prismjs'\nimport 'prismjs"
  },
  {
    "path": "examples/hello/src/index.tsx",
    "chars": 720,
    "preview": "import { createRoot } from 'react-dom/client'\nimport App from './App'\nimport './prism.css'\nimport './style.css'\n\nconst r"
  },
  {
    "path": "examples/hello/src/prism.css",
    "chars": 3102,
    "preview": "/**\n * VS theme by Andrew Lock (https://andrewlock.net)\n * Inspired by Visual Studio syntax coloring\n */\n\ncode[class*='l"
  },
  {
    "path": "examples/hello/src/style.css",
    "chars": 1038,
    "preview": "@import url('https://rsms.me/inter/inter.css');\nhtml {\n  font-family: 'Inter', sans-serif;\n}\n\n@supports (font-variation-"
  },
  {
    "path": "examples/hello/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/hello/tsconfig.json",
    "chars": 544,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es2019\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDef"
  },
  {
    "path": "examples/hello/vite.config.ts",
    "chars": 133,
    "preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n  plugins: ["
  },
  {
    "path": "examples/mega-form/README.md",
    "chars": 581,
    "preview": "# Mega form [![Open in StackBlitz](https://img.shields.io/badge/Open%20in-StackBlitz-blue?style=flat-square&logo=stackbl"
  },
  {
    "path": "examples/mega-form/index.html",
    "chars": 374,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/mega-form/package.json",
    "chars": 554,
    "preview": "{\n  \"name\": \"mega-form\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"tsc &"
  },
  {
    "path": "examples/mega-form/public/index.html",
    "chars": 362,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/mega-form/src/App.tsx",
    "chars": 3869,
    "preview": "import { useCallback, useMemo } from 'react'\nimport { Provider, atom, useAtom } from 'jotai'\nimport type { PrimitiveAtom"
  },
  {
    "path": "examples/mega-form/src/index.tsx",
    "chars": 185,
    "preview": "import { createRoot } from 'react-dom/client'\nimport App from './App'\nimport './style.css'\n\nconst rootElement = document"
  },
  {
    "path": "examples/mega-form/src/initialValue.ts",
    "chars": 1814,
    "preview": "const initialValue: Record<string, Record<string, string>> = {\n  form1: { task: 'Eat some food', checked: 'yeah' },\n  fo"
  },
  {
    "path": "examples/mega-form/src/style.css",
    "chars": 930,
    "preview": "html,\nbody {\n  position: relative;\n  width: 100%;\n  height: 100%;\n}\n\nbody {\n  color: #333;\n  margin: 0;\n  padding: 8px;\n"
  },
  {
    "path": "examples/mega-form/src/useAtomSlice.ts",
    "chars": 558,
    "preview": "import { useMemo } from 'react'\nimport { useAtom } from 'jotai'\nimport type { PrimitiveAtom } from 'jotai'\nimport { spli"
  },
  {
    "path": "examples/mega-form/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/mega-form/tsconfig.json",
    "chars": 544,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es2019\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDef"
  },
  {
    "path": "examples/mega-form/vite.config.ts",
    "chars": 133,
    "preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n  plugins: ["
  },
  {
    "path": "examples/starter/README.md",
    "chars": 573,
    "preview": "# Starter [![Open in StackBlitz](https://img.shields.io/badge/Open%20in-StackBlitz-blue?style=flat-square&logo=stackblit"
  },
  {
    "path": "examples/starter/index.html",
    "chars": 469,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <"
  },
  {
    "path": "examples/starter/package.json",
    "chars": 469,
    "preview": "{\n  \"name\": \"starter\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n  "
  },
  {
    "path": "examples/starter/src/index.css",
    "chars": 168,
    "preview": "html,\nbody,\n#root {\n  height: 100%;\n}\n\n#root {\n  display: flex;\n  place-items: center;\n  justify-content: center;\n\n  col"
  },
  {
    "path": "examples/starter/src/index.tsx",
    "chars": 1096,
    "preview": "import { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { atom, useAtom } from 'jotai'\n\n"
  },
  {
    "path": "examples/starter/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/starter/tsconfig.json",
    "chars": 562,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es2019\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDef"
  },
  {
    "path": "examples/starter/vite.config.ts",
    "chars": 163,
    "preview": "import react from '@vitejs/plugin-react'\nimport { defineConfig } from 'vite'\n\n// https://vitejs.dev/config/\nexport defau"
  },
  {
    "path": "examples/text_length/README.md",
    "chars": 659,
    "preview": "# Text Length [![Open in StackBlitz](https://img.shields.io/badge/Open%20in-StackBlitz-blue?style=flat-square&logo=stack"
  },
  {
    "path": "examples/text_length/index.html",
    "chars": 1068,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/text_length/package.json",
    "chars": 524,
    "preview": "{\n  \"name\": \"text_length\",\n  \"version\": \"2.0.0\",\n  \"description\": \"Count the length and show the uppercase of any text\","
  },
  {
    "path": "examples/text_length/public/index.html",
    "chars": 4096,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta\n      name=\"viewport\"\n      content=\"wi"
  },
  {
    "path": "examples/text_length/src/App.tsx",
    "chars": 681,
    "preview": "import { Provider, atom, useAtom } from 'jotai'\n\nconst textAtom = atom('hello')\nconst textLenAtom = atom((get) => get(te"
  },
  {
    "path": "examples/text_length/src/index.tsx",
    "chars": 237,
    "preview": "import { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport App from './App'\n\nconst rootElem"
  },
  {
    "path": "examples/text_length/src/react-app-env.d.ts",
    "chars": 40,
    "preview": "/// <reference types=\"react-scripts\" />\n"
  },
  {
    "path": "examples/text_length/tsconfig.json",
    "chars": 544,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es2019\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDef"
  },
  {
    "path": "examples/text_length/vite.config.ts",
    "chars": 133,
    "preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n  plugins: ["
  },
  {
    "path": "examples/todos/README.md",
    "chars": 758,
    "preview": "# Todos [![Open in StackBlitz](https://img.shields.io/badge/Open%20in-StackBlitz-blue?style=flat-square&logo=stackblitz)"
  },
  {
    "path": "examples/todos/index.html",
    "chars": 360,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/todos/package.json",
    "chars": 610,
    "preview": "{\n  \"name\": \"todos\",\n  \"version\": \"2.0.0\",\n  \"description\": \"Record your todo list by typing them into this app\",\n  \"typ"
  },
  {
    "path": "examples/todos/public/index.html",
    "chars": 1620,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta\n      name=\"viewport\"\n      content=\"wi"
  },
  {
    "path": "examples/todos/src/App.tsx",
    "chars": 2926,
    "preview": "import type { FormEvent } from 'react'\nimport { CloseOutlined } from '@ant-design/icons'\nimport { a, useTransition } fro"
  },
  {
    "path": "examples/todos/src/index.tsx",
    "chars": 214,
    "preview": "import { createRoot } from 'react-dom/client'\nimport 'antd/dist/antd.css'\nimport './styles.css'\nimport App from './App'\n"
  },
  {
    "path": "examples/todos/src/styles.css",
    "chars": 1188,
    "preview": "@import url('https://rsms.me/inter/inter.css');\n\n* {\n  box-sizing: border-box;\n}\n\nhtml,\nbody {\n  width: 100%;\n  height: "
  },
  {
    "path": "examples/todos/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/todos/tsconfig.json",
    "chars": 307,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es2019\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDef"
  },
  {
    "path": "examples/todos/vite.config.ts",
    "chars": 133,
    "preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n  plugins: ["
  },
  {
    "path": "examples/todos_with_atomFamily/README.md",
    "chars": 1057,
    "preview": "# Todos with atomFamily [![Open in StackBlitz](https://img.shields.io/badge/Open%20in-StackBlitz-blue?style=flat-square&"
  },
  {
    "path": "examples/todos_with_atomFamily/index.html",
    "chars": 376,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/todos_with_atomFamily/package.json",
    "chars": 656,
    "preview": "{\n  \"name\": \"todos_with_atomFamily\",\n  \"version\": \"2.0.0\",\n  \"description\": \"Implement a todo list using atomFamily and "
  },
  {
    "path": "examples/todos_with_atomFamily/public/index.html",
    "chars": 1636,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta\n      name=\"viewport\"\n      content=\"wi"
  },
  {
    "path": "examples/todos_with_atomFamily/src/App.tsx",
    "chars": 4511,
    "preview": "import type { FormEvent } from 'react'\nimport { CloseOutlined } from '@ant-design/icons'\nimport { a, useTransition } fro"
  },
  {
    "path": "examples/todos_with_atomFamily/src/index.tsx",
    "chars": 214,
    "preview": "import { createRoot } from 'react-dom/client'\nimport 'antd/dist/antd.css'\nimport './styles.css'\nimport App from './App'\n"
  },
  {
    "path": "examples/todos_with_atomFamily/src/styles.css",
    "chars": 1188,
    "preview": "@import url('https://rsms.me/inter/inter.css');\n\n* {\n  box-sizing: border-box;\n}\n\nhtml,\nbody {\n  width: 100%;\n  height: "
  },
  {
    "path": "examples/todos_with_atomFamily/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "examples/todos_with_atomFamily/tsconfig.json",
    "chars": 544,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es2019\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDef"
  },
  {
    "path": "examples/todos_with_atomFamily/vite.config.ts",
    "chars": 133,
    "preview": "import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n  plugins: ["
  },
  {
    "path": "package.json",
    "chars": 6786,
    "preview": "{\n  \"name\": \"jotai\",\n  \"description\": \"👻 Primitive and flexible state management for React\",\n  \"private\": true,\n  \"type\""
  },
  {
    "path": "pnpm-workspace.yaml",
    "chars": 110,
    "preview": "packages:\n  - .\nminimumReleaseAge: 1440\nminimumReleaseAgeExclude:\n  - 'react'\n  - 'react-dom'\n  - 'scheduler'\n"
  },
  {
    "path": "rollup.config.mjs",
    "chars": 5606,
    "preview": "/*global process*/\nimport path from 'path'\nimport alias from '@rollup/plugin-alias'\nimport babelPlugin from '@rollup/plu"
  },
  {
    "path": "src/babel/plugin-debug-label.ts",
    "chars": 2345,
    "preview": "import babel from '@babel/core'\nimport type { PluginObj } from '@babel/core'\nimport _templateBuilder from '@babel/templa"
  },
  {
    "path": "src/babel/plugin-react-refresh.ts",
    "chars": 3020,
    "preview": "import babel from '@babel/core'\nimport type { PluginObj } from '@babel/core'\nimport _templateBuilder from '@babel/templa"
  },
  {
    "path": "src/babel/preset.ts",
    "chars": 676,
    "preview": "import babel from '@babel/core'\nimport pluginDebugLabel from './plugin-debug-label.ts'\nimport pluginReactRefresh from '."
  },
  {
    "path": "src/babel/utils.ts",
    "chars": 1361,
    "preview": "import { types } from '@babel/core'\n\nexport interface PluginOptions {\n  customAtomNames?: string[]\n}\n\nexport function is"
  },
  {
    "path": "src/index.ts",
    "chars": 56,
    "preview": "export * from './vanilla.ts'\nexport * from './react.ts'\n"
  },
  {
    "path": "src/react/Provider.ts",
    "chars": 1301,
    "preview": "import { createContext, createElement, useContext, useRef } from 'react'\nimport type { FunctionComponent, ReactElement, "
  },
  {
    "path": "src/react/useAtom.ts",
    "chars": 1520,
    "preview": "import type {\n  Atom,\n  ExtractAtomArgs,\n  ExtractAtomResult,\n  ExtractAtomValue,\n  PrimitiveAtom,\n  SetStateAction,\n  W"
  },
  {
    "path": "src/react/useAtomValue.ts",
    "chars": 4894,
    "preview": "import React, { useDebugValue, useEffect, useReducer } from 'react'\nimport { INTERNAL_getBuildingBlocksRev2 as INTERNAL_"
  },
  {
    "path": "src/react/useSetAtom.ts",
    "chars": 1194,
    "preview": "import { useCallback } from 'react'\nimport type {\n  ExtractAtomArgs,\n  ExtractAtomResult,\n  WritableAtom,\n} from '../van"
  },
  {
    "path": "src/react/utils/useAtomCallback.ts",
    "chars": 567,
    "preview": "import { useMemo } from 'react'\nimport { useSetAtom } from '../../react.ts'\nimport { atom } from '../../vanilla.ts'\nimpo"
  },
  {
    "path": "src/react/utils/useHydrateAtoms.ts",
    "chars": 1754,
    "preview": "import { useStore } from '../../react.ts'\nimport { type WritableAtom } from '../../vanilla.ts'\n\ntype Store = ReturnType<"
  },
  {
    "path": "src/react/utils/useReducerAtom.ts",
    "chars": 1358,
    "preview": "import { useCallback } from 'react'\nimport { useAtom } from '../../react.ts'\nimport type { PrimitiveAtom } from '../../v"
  },
  {
    "path": "src/react/utils/useResetAtom.ts",
    "chars": 481,
    "preview": "import { useCallback } from 'react'\nimport { useSetAtom } from '../../react.ts'\nimport { RESET } from '../../vanilla/uti"
  },
  {
    "path": "src/react/utils.ts",
    "chars": 236,
    "preview": "export { useResetAtom } from './utils/useResetAtom.ts'\nexport { useReducerAtom } from './utils/useReducerAtom.ts'\nexport"
  },
  {
    "path": "src/react.ts",
    "chars": 208,
    "preview": "export { Provider, useStore } from './react/Provider.ts'\nexport { useAtomValue } from './react/useAtomValue.ts'\nexport {"
  },
  {
    "path": "src/types.d.ts",
    "chars": 64,
    "preview": "declare interface ImportMeta {\n  env?: {\n    MODE: string\n  }\n}\n"
  },
  {
    "path": "src/utils.ts",
    "chars": 68,
    "preview": "export * from './vanilla/utils.ts'\nexport * from './react/utils.ts'\n"
  },
  {
    "path": "src/vanilla/atom.ts",
    "chars": 3600,
    "preview": "import type { Store } from './store'\n\ntype Getter = <Value>(atom: Atom<Value>) => Value\n\ntype Setter = <Value, Args exte"
  },
  {
    "path": "src/vanilla/internals.ts",
    "chars": 34630,
    "preview": "// Internal functions (subject to change without notice)\n// In case you rely on them, be sure to pin the version\n\nimport"
  },
  {
    "path": "src/vanilla/store.ts",
    "chars": 1107,
    "preview": "import { INTERNAL_buildStoreRev2 as INTERNAL_buildStore } from './internals.ts'\nimport type { INTERNAL_Store } from './i"
  },
  {
    "path": "src/vanilla/typeUtils.ts",
    "chars": 658,
    "preview": "import type { Atom, PrimitiveAtom, WritableAtom } from './atom.ts'\n\nexport type Getter = Parameters<Atom<unknown>['read'"
  },
  {
    "path": "src/vanilla/utils/atomFamily.ts",
    "chars": 4128,
    "preview": "import { type Atom } from '../../vanilla.ts'\n\n/**\n * in milliseconds\n */\ntype CreatedAt = number\ntype ShouldRemove<Param"
  },
  {
    "path": "src/vanilla/utils/atomWithDefault.ts",
    "chars": 1254,
    "preview": "import { atom } from '../../vanilla.ts'\nimport type { WritableAtom } from '../../vanilla.ts'\nimport { RESET } from './co"
  },
  {
    "path": "src/vanilla/utils/atomWithLazy.ts",
    "chars": 373,
    "preview": "import { atom } from '../../vanilla.ts'\nimport type { PrimitiveAtom } from '../../vanilla.ts'\n\nexport function atomWithL"
  },
  {
    "path": "src/vanilla/utils/atomWithObservable.ts",
    "chars": 5290,
    "preview": "import { atom } from '../../vanilla.ts'\nimport type { Atom, Getter, WritableAtom } from '../../vanilla.ts'\n\nconst isProm"
  },
  {
    "path": "src/vanilla/utils/atomWithReducer.ts",
    "chars": 677,
    "preview": "import { atom } from '../../vanilla.ts'\nimport type { WritableAtom } from '../../vanilla.ts'\n\nexport function atomWithRe"
  },
  {
    "path": "src/vanilla/utils/atomWithRefresh.ts",
    "chars": 1294,
    "preview": "import { atom } from '../../vanilla.ts'\nimport type { WritableAtom } from '../../vanilla.ts'\n\ntype Read<Value, Args exte"
  },
  {
    "path": "src/vanilla/utils/atomWithReset.ts",
    "chars": 1014,
    "preview": "import { atom } from '../../vanilla.ts'\nimport type { WritableAtom } from '../../vanilla.ts'\nimport { RESET } from './co"
  },
  {
    "path": "src/vanilla/utils/atomWithStorage.ts",
    "chars": 7368,
    "preview": "import { atom } from '../../vanilla.ts'\nimport type { WritableAtom } from '../../vanilla.ts'\nimport { RESET } from './co"
  }
]

// ... and 126 more files (download for full content)

About this extraction

This page contains the full source code of the pmndrs/jotai GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 326 files (960.9 KB), approximately 277.2k tokens, and a symbol index with 258 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!