Top Related Projects
Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.
A JS library for predictable global state management
Simple, scalable state management.
Actor-based state management & orchestration for complex app logic.
Manage state with style in every framework
Quick Overview
Jotai is a primitive and flexible state management library for React. It provides a minimalistic API for managing global state in React applications, focusing on simplicity and composability. Jotai uses the concept of atoms to represent pieces of state, which can be easily shared and updated across components.
Pros
- Lightweight and has a small bundle size
- Simple API with a low learning curve
- Supports TypeScript out of the box
- Integrates well with React's concurrent features
Cons
- Less suitable for complex state management scenarios compared to more robust solutions like Redux
- Limited ecosystem and tooling compared to more established state management libraries
- May require additional setup for advanced features like persistence or debugging
Code Examples
- Creating and using a basic atom:
import { atom, useAtom } from 'jotai'
const countAtom = atom(0)
function Counter() {
const [count, setCount] = useAtom(countAtom)
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
)
}
- Creating a derived atom:
import { atom, useAtom } from 'jotai'
const countAtom = atom(0)
const doubleCountAtom = atom(get => get(countAtom) * 2)
function DoubleCounter() {
const [count] = useAtom(countAtom)
const [doubleCount] = useAtom(doubleCountAtom)
return <div>Count: {count}, Double: {doubleCount}</div>
}
- Async atom:
import { atom, useAtom } from 'jotai'
const userAtom = atom(async () => {
const response = await fetch('https://api.example.com/user')
return response.json()
})
function User() {
const [user] = useAtom(userAtom)
return <div>{user.name}</div>
}
Getting Started
To start using Jotai in your React project:
- Install Jotai:
npm install jotai
- Create and use an atom in your component:
import { atom, useAtom } from 'jotai'
const textAtom = atom('Hello')
function MyComponent() {
const [text, setText] = useAtom(textAtom)
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} />
<p>Text: {text}</p>
</div>
)
}
Competitor Comparisons
Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.
Pros of Recoil
- More mature and battle-tested in large-scale applications
- Offers advanced features like atom effects and selectors
- Backed by Facebook, potentially ensuring long-term support
Cons of Recoil
- Larger bundle size and more complex API
- Steeper learning curve for beginners
- Requires wrapping the entire app in a RecoilRoot component
Code Comparison
Recoil:
import { atom, useRecoilState } from 'recoil';
const countState = atom({
key: 'countState',
default: 0,
});
function Counter() {
const [count, setCount] = useRecoilState(countState);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Jotai:
import { atom, useAtom } from 'jotai';
const countAtom = atom(0);
function Counter() {
const [count, setCount] = useAtom(countAtom);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Both Recoil and Jotai are state management libraries for React applications, focusing on atomic state management. Recoil offers more features and is suitable for complex applications, while Jotai provides a simpler API and smaller bundle size, making it ideal for smaller projects or those prioritizing performance.
A JS library for predictable global state management
Pros of Redux
- Well-established ecosystem with extensive tooling and middleware
- Centralized state management for complex applications
- Time-travel debugging and predictable state updates
Cons of Redux
- Boilerplate code required for setup and actions
- Steep learning curve for beginners
- Can be overkill for small to medium-sized applications
Code Comparison
Redux:
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
default:
return state
}
}
Jotai:
import { atom } from 'jotai'
const counterAtom = atom(0)
const incrementAtom = atom(
(get) => get(counterAtom),
(get, set) => set(counterAtom, get(counterAtom) + 1)
)
Redux requires defining reducers and action creators, while Jotai uses atoms for state management. Jotai's approach is more concise and requires less boilerplate. Redux offers a more structured approach to state management, which can be beneficial for larger applications. Jotai provides a simpler API that may be easier for beginners to grasp and quicker to implement in smaller projects.
Simple, scalable state management.
Pros of MobX
- More mature and established library with a larger ecosystem
- Supports complex state management scenarios with computed values and reactions
- Offers better performance for large-scale applications with many observers
Cons of MobX
- Steeper learning curve due to more concepts and decorators
- Requires more boilerplate code for setting up stores and actions
- Less aligned with React's functional programming paradigm
Code Comparison
MobX:
import { makeAutoObservable } from "mobx";
class TodoStore {
todos = [];
constructor() {
makeAutoObservable(this);
}
addTodo(text) {
this.todos.push({ text, completed: false });
}
}
Jotai:
import { atom } from "jotai";
const todosAtom = atom([]);
const addTodoAtom = atom(
null,
(get, set, text) => set(todosAtom, [...get(todosAtom), { text, completed: false }])
);
Jotai offers a more lightweight and React-friendly approach to state management, with a focus on simplicity and composability. It uses atoms as the basic unit of state, which can be easily combined and shared across components. MobX, on the other hand, provides a more robust solution for complex state management scenarios, with features like computed values and reactions. The choice between the two depends on the specific needs of your project and your preferred programming style.
Actor-based state management & orchestration for complex app logic.
Pros of XState
- More powerful for complex state management with hierarchical and parallel states
- Visual editor (XState Viz) for designing and debugging state machines
- Extensive documentation and community support
Cons of XState
- Steeper learning curve due to its more complex API and concepts
- Potentially overkill for simple state management needs
- Larger bundle size compared to Jotai's lightweight approach
Code Comparison
XState:
import { createMachine, interpret } from 'xstate';
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: { on: { TOGGLE: 'active' } },
active: { on: { TOGGLE: 'inactive' } }
}
});
Jotai:
import { atom, useAtom } from 'jotai';
const toggleAtom = atom(false);
const Toggle = () => {
const [isActive, setIsActive] = useAtom(toggleAtom);
return <button onClick={() => setIsActive(!isActive)}>Toggle</button>;
};
XState offers a more structured approach to state management, suitable for complex applications with many states and transitions. Jotai, on the other hand, provides a simpler, atom-based state management solution that's easier to grasp and implement for basic use cases.
Manage state with style in every framework
Pros of Signals
- Lightweight and fast, with a smaller bundle size
- Designed specifically for Preact, offering tight integration
- Simple API with a focus on ease of use
Cons of Signals
- Limited to Preact ecosystem, less versatile across frameworks
- Fewer advanced features compared to Jotai's rich ecosystem
- Less community adoption and third-party integrations
Code Comparison
Signals:
import { signal } from "@preact/signals";
const count = signal(0);
const increment = () => count.value++;
return <button onClick={increment}>{count}</button>;
Jotai:
import { atom, useAtom } from "jotai";
const countAtom = atom(0);
const Counter = () => {
const [count, setCount] = useAtom(countAtom);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
};
Both Signals and Jotai provide state management solutions, but they cater to different needs. Signals is tailored for Preact and offers a simpler API, while Jotai is more versatile and feature-rich, supporting various React-based frameworks. The choice between them depends on the specific project requirements, framework preferences, and desired level of complexity in state management.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
visit jotai.org or npm i 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)
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.
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
:
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.
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.
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 ...
const atoms = [count1, count2, count3, ...otherAtoms]
const sum = atom((get) => atoms.map(get).reduce((acc, count) => acc + count))
Derived async atoms
You can make the read function an async function too.
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.
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.
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.
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 pattern for modular, pure, robust and understandable code which is optimized for change. Read more about Jotai and monads.
Links
Top Related Projects
Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.
A JS library for predictable global state management
Simple, scalable state management.
Actor-based state management & orchestration for complex app logic.
Manage state with style in every framework
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot