1 | <p align="center">
|
2 | <img src="img/title.svg" alt="jotai" />
|
3 | </p>
|
4 |
|
5 | Primitive and flexible state management for React
|
6 |
|
7 | `npm i jotai`
|
8 |
|
9 | [![Build Status](https://img.shields.io/github/workflow/status/pmndrs/jotai/Lint?style=flat&colorA=000000&colorB=000000)](https://github.com/pmndrs/jotai/actions?query=workflow%3ALint)
|
10 | [![Build Size](https://img.shields.io/bundlephobia/min/jotai?label=bundle%20size&style=flat&colorA=000000&colorB=000000)](https://bundlephobia.com/result?p=jotai)
|
11 | [![Version](https://img.shields.io/npm/v/jotai?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/jotai)
|
12 | [![Downloads](https://img.shields.io/npm/dt/jotai.svg?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/jotai)
|
13 | [![Discord Shield](https://img.shields.io/discord/740090768164651008?style=flat&colorA=000000&colorB=000000&label=discord&logo=discord&logoColor=ffffff)](https://discord.gg/poimandres)
|
14 | [![Open Collective](https://img.shields.io/opencollective/all/jotai?style=flat&colorA=000000&colorB=000000)](https://opencollective.com/jotai)
|
15 |
|
16 | Jotai is pronounced "joe-tie" and means "state" in Japanese.
|
17 |
|
18 | You can try live demos in the following:
|
19 | [Demo 1](https://codesandbox.io/s/jotai-demo-47wvh) |
|
20 | [Demo 2](https://codesandbox.io/s/jotai-demo-forked-x2g5d).
|
21 |
|
22 | #### How does Jotai differ from Recoil?
|
23 |
|
24 | - Minimalistic API
|
25 | - No string keys
|
26 | - TypeScript oriented
|
27 |
|
28 | ### First create a primitive atom
|
29 |
|
30 | An atom represents a piece of state. All you need is to specify an initial
|
31 | value, which can be primitive values like strings and numbers, objects and
|
32 | arrays. You can create as many primitive atoms as you want.
|
33 |
|
34 | ```jsx
|
35 | import { atom } from 'jotai'
|
36 |
|
37 | const countAtom = atom(0)
|
38 | const countryAtom = atom('Japan')
|
39 | const citiesAtom = atom(['Tokyo', 'Kyoto', 'Osaka'])
|
40 | const mangaAtom = atom({ 'Dragon Ball': 1984, 'One Piece': 1997, Naruto: 1999 })
|
41 | ```
|
42 |
|
43 | ### Use the atom in your components
|
44 |
|
45 | It can be used like `React.useState`:
|
46 |
|
47 | ```jsx
|
48 | import { useAtom } from 'jotai'
|
49 |
|
50 | function Counter() {
|
51 | const [count, setCount] = useAtom(countAtom)
|
52 | return (
|
53 | <h1>
|
54 | {count}
|
55 | <button onClick={() => setCount(c => c + 1)}>one up</button>
|
56 | ```
|
57 |
|
58 | ### Create derived atoms with computed values
|
59 |
|
60 | A new read-only atom can be created from existing atoms by passing a read
|
61 | function as the first argument. `get` allows you to fetch the contextual value
|
62 | of any atom.
|
63 |
|
64 | ```jsx
|
65 | const doubledCountAtom = atom((get) => get(countAtom) * 2)
|
66 |
|
67 | function DoubleCounter() {
|
68 | const [doubledCount] = useAtom(doubledCountAtom)
|
69 | return <h2>{doubledCount}</h2>
|
70 | ```
|
71 |
|
72 | ## Recipes
|
73 |
|
74 | ### Creating an atom from multiple atoms
|
75 |
|
76 | You can combine multiple atoms to create a derived atom.
|
77 |
|
78 | ```jsx
|
79 | const count1 = atom(1)
|
80 | const count2 = atom(2)
|
81 | const count3 = atom(3)
|
82 |
|
83 | const sum = atom((get) => get(count1) + get(count2) + get(count3))
|
84 | ```
|
85 |
|
86 | Or if you like fp patterns ...
|
87 |
|
88 | ```jsx
|
89 | const atoms = [count1, count2, count3, ...otherAtoms]
|
90 | const sum = atom((get) => atoms.map(get).reduce((acc, count) => acc + count))
|
91 | ```
|
92 |
|
93 | ### Derived async atoms <img src="https://img.shields.io/badge/-needs_suspense-black" alt="needs suspense" />
|
94 |
|
95 | You can make the read function an async function too.
|
96 |
|
97 | ```jsx
|
98 | const urlAtom = atom("https://json.host.com")
|
99 | const fetchUrlAtom = atom(
|
100 | async (get) => {
|
101 | const response = await fetch(get(urlAtom))
|
102 | return await response.json()
|
103 | }
|
104 | )
|
105 |
|
106 | function Status() {
|
107 | // Re-renders the component after urlAtom changed and the async function above concludes
|
108 | const [json] = useAtom(fetchUrlAtom)
|
109 | ```
|
110 |
|
111 | ### You can create a writable derived atom
|
112 |
|
113 | Specify a write function at the second argument. `get` will return the current
|
114 | value of an atom. `set` will update an atoms value.
|
115 |
|
116 | ```jsx
|
117 | const decrementCountAtom = atom(
|
118 | (get) => get(countAtom),
|
119 | (get, set, _arg) => set(countAtom, get(countAtom) - 1),
|
120 | )
|
121 |
|
122 | function Counter() {
|
123 | const [count, decrement] = useAtom(decrementCountAtom)
|
124 | return (
|
125 | <h1>
|
126 | {count}
|
127 | <button onClick={decrement}>Decrease</button>
|
128 | ```
|
129 |
|
130 | ### Write only atoms
|
131 |
|
132 | Just do not define a read function.
|
133 |
|
134 | ```jsx
|
135 | const multiplyCountAtom = atom(null, (get, set, by) => set(countAtom, get(countAtom) * by))
|
136 |
|
137 | function Controls() {
|
138 | const [, multiply] = useAtom(multiplyCountAtom)
|
139 | return <button onClick={() => multiply(3)}>triple</button>
|
140 | ```
|
141 |
|
142 | ### Async actions <img src="https://img.shields.io/badge/-needs_suspense-black" alt="needs suspense" />
|
143 |
|
144 | Just make the write function an async function and call `set` when you're ready.
|
145 |
|
146 | ```jsx
|
147 | const fetchCountAtom = atom(
|
148 | (get) => get(countAtom),
|
149 | async (_get, set, url) => {
|
150 | const response = await fetch(url)
|
151 | set(countAtom, (await response.json()).count)
|
152 | }
|
153 | )
|
154 |
|
155 | function Controls() {
|
156 | const [count, compute] = useAtom(fetchCountAtom)
|
157 | return <button onClick={() => compute("http://count.host.com")}>compute</button>
|
158 | ```
|
159 |
|
160 | ## Installation notes
|
161 |
|
162 | This package requires some peer dependencies, which you need to install by
|
163 | yourself.
|
164 |
|
165 | ```bash
|
166 | yarn add jotai react
|
167 | ```
|
168 |
|
169 | ## More documents
|
170 |
|
171 | - Overview
|
172 | - [Introduction](https://docs.pmnd.rs/jotai/introduction)
|
173 | - Basics
|
174 | - [Concepts](https://docs.pmnd.rs/jotai/basics/concepts)
|
175 | - [Primitives](https://docs.pmnd.rs/jotai/basics/primitives)
|
176 | - [Async](https://docs.pmnd.rs/jotai/basics/async)
|
177 | - [Comparison](https://docs.pmnd.rs/jotai/basics/comparison)
|
178 | - [Showcase](https://docs.pmnd.rs/jotai/basics/showcase)
|
179 | - Guides
|
180 | - [TypeScript](https://docs.pmnd.rs/jotai/guides/typescript)
|
181 | - [Debugging](https://docs.pmnd.rs/jotai/guides/debugging)
|
182 | - [Persistence](https://docs.pmnd.rs/jotai/guides/persistence)
|
183 | - [Next.js](https://docs.pmnd.rs/jotai/guides/nextjs)
|
184 | - [Resettable](https://docs.pmnd.rs/jotai/guides/resettable)
|
185 | - [No Suspense](https://docs.pmnd.rs/jotai/guides/no-suspense)
|
186 | - [Atoms in atom](https://docs.pmnd.rs/jotai/guides/atoms-in-atom)
|
187 | - API
|
188 | - [Core](https://docs.pmnd.rs/jotai/api/core)
|
189 | - [Utils](https://docs.pmnd.rs/jotai/api/utils)
|
190 | - [Devtools](https://docs.pmnd.rs/jotai/api/devtools)
|
191 | - [Immer](https://docs.pmnd.rs/jotai/integrations/immer) ([immer](https://github.com/immerjs/immer) integration)
|
192 | - [Optics](https://docs.pmnd.rs/jotai/integrations/optics) ([optics-ts](https://github.com/akheron/optics-ts) integration)
|
193 | - [Query](https://docs.pmnd.rs/jotai/integrations/query) ([react-query](https://github.com/tannerlinsley/react-query) integration)
|
194 | - [XState](https://docs.pmnd.rs/jotai/integrations/xstate) ([xstate](https://github.com/davidkpiano/xstate) integration)
|
195 | - [Valtio](https://docs.pmnd.rs/jotai/integrations/valtio) ([valtio](https://github.com/pmndrs/valtio) integration)
|
196 | - [Zustand](https://docs.pmnd.rs/jotai/integrations/zustand) ([zustand](https://github.com/pmndrs/zustand) integration)
|
197 | - [Redux](https://docs.pmnd.rs/jotai/integrations/redux) ([redux](https://github.com/reduxjs/redux) integration)
|
198 | - Advanced Recipes
|
199 | - [Large Objects](https://docs.pmnd.rs/jotai/advanced-recipes/large-objects)
|