Primitive and flexible state management for React applications
npx @tessl/cli install tessl/npm-jotai@2.13.0Jotai is a primitive and flexible state management library for React applications that scales from simple useState replacements to enterprise TypeScript applications. It provides atom-based state management without string keys, featuring a minimal 2kb core API with extensive utilities and extensions.
npm install jotaiimport { atom, useAtom, useAtomValue, useSetAtom, Provider } from "jotai";For CommonJS:
const { atom, useAtom, useAtomValue, useSetAtom, Provider } = require("jotai");Utility imports:
import { atomWithStorage, atomWithReset, loadable, RESET } from "jotai/utils";import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
// Create atoms
const countAtom = atom(0);
const doubleCountAtom = atom((get) => get(countAtom) * 2);
const incrementAtom = atom(null, (get, set) => {
set(countAtom, get(countAtom) + 1);
});
// Use in React components
function Counter() {
const [count, setCount] = useAtom(countAtom);
const doubleCount = useAtomValue(doubleCountAtom);
const increment = useSetAtom(incrementAtom);
return (
<div>
<p>Count: {count}</p>
<p>Double: {doubleCount}</p>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<button onClick={increment}>Increment via Action</button>
</div>
);
}Jotai is built around several key concepts:
Basic atom creation and type definitions for building reactive state.
function atom<Value>(initialValue: Value): PrimitiveAtom<Value>;
function atom<Value>(read: Read<Value>): Atom<Value>;
function atom<Value, Args extends unknown[], Result>(
read: Read<Value>,
write: Write<Args, Result>
): WritableAtom<Value, Args, Result>;
interface Atom<Value> {
toString: () => string;
read: Read<Value>;
debugLabel?: string;
}
interface WritableAtom<Value, Args extends unknown[], Result> extends Atom<Value> {
write: Write<Args, Result>;
onMount?: OnMount<Args, Result>;
}
type PrimitiveAtom<Value> = WritableAtom<Value, [SetStateAction<Value>], void>;React hooks and components for integrating atoms with React applications.
function useAtom<Value, Args extends unknown[], Result>(
atom: WritableAtom<Value, Args, Result>,
options?: Options
): [Awaited<Value>, SetAtom<Args, Result>];
function useAtomValue<Value>(
atom: Atom<Value>,
options?: Options
): Awaited<Value>;
function useSetAtom<Value, Args extends unknown[], Result>(
atom: WritableAtom<Value, Args, Result>,
options?: Options
): SetAtom<Args, Result>;
function Provider(props: {
children?: ReactNode;
store?: Store;
}): ReactElement;Core utility functions for advanced atom patterns and functionality.
const RESET: unique symbol;
function atomWithReset<Value>(
initialValue: Value
): WritableAtom<Value, [SetStateAction<Value> | typeof RESET], void>;
function atomFamily<Param, AtomType>(
initializeAtom: (param: Param) => AtomType,
areEqual?: (a: Param, b: Param) => boolean
): AtomFamily<Param, AtomType>;
function atomWithStorage<Value>(
key: string,
initialValue: Value,
storage?: SyncStorage<Value> | AsyncStorage<Value>
): WritableAtom<Value, [SetStateAction<Value>], void>;
function loadable<Value>(anAtom: Atom<Value>): Atom<Loadable<Value>>;React-specific utility hooks for advanced patterns and functionality.
function useResetAtom<T>(
anAtom: WritableAtom<unknown, [typeof RESET], T>,
options?: Options
): () => T;
function useAtomCallback<Result, Args extends unknown[]>(
callback: (get: Getter, set: Setter, ...args: Args) => Result,
options?: Options
): (...args: Args) => Result;
function useHydrateAtoms<Values extends readonly (readonly [Atom<unknown>, unknown])[]>(
values: Values,
options?: Options
): void;type Getter = <Value>(atom: Atom<Value>) => Value;
type Setter = <Value, Args extends unknown[], Result>(
atom: WritableAtom<Value, Args, Result>,
...args: Args
) => Result;
type SetStateAction<Value> = Value | ((prev: Value) => Value);
type ExtractAtomValue<AtomType> = AtomType extends Atom<infer Value> ? Value : never;
type ExtractAtomArgs<AtomType> = AtomType extends WritableAtom<any, infer Args, any> ? Args : never;
type ExtractAtomResult<AtomType> = AtomType extends WritableAtom<any, any, infer Result> ? Result : never;interface Store {
get: <Value>(atom: Atom<Value>) => Value;
set: <Value, Args extends unknown[], Result>(
atom: WritableAtom<Value, Args, Result>,
...args: Args
) => Result;
sub: (atom: AnyAtom, listener: Listener) => Unsubscribe;
}
function createStore(): Store;
function getDefaultStore(): Store;interface SyncStorage<Value> {
getItem: (key: string, initialValue: Value) => Value;
setItem: (key: string, value: Value) => void;
removeItem: (key: string) => void;
}
interface AsyncStorage<Value> {
getItem: (key: string, initialValue: Value) => Promise<Value>;
setItem: (key: string, value: Value) => Promise<void>;
removeItem: (key: string) => Promise<void>;
}
type Loadable<Value> =
| { state: "loading" }
| { state: "hasError"; error: unknown }
| { state: "hasData"; data: Value };