JotaiJotai

状態
Primitive and flexible state management for React
Jotai mascot
No extra re-renders, state resides within React, and you get the full benefits from suspense and concurrent features.
It’s scalable from a simple React.useState replacement to a large-scale application with complex requirements.

Introduction

Jotai takes a bottom-up approach to React state management with an atomic model inspired by Recoil. One can build state by combining atoms and renders are optimized based on atom dependency. This solves the extra re-render issue of React context and eliminates the need for the memoization technique.

Core API

Jotai has a very minimal API and is TypeScript oriented. It is as simple to use as React’s integrated useState hook, but all state is globally accessible, derived state is easy to implement, and extra re-renders are automatically eliminated.

HELLO
import { atom, useAtom } from 'jotai'
// Create your atoms and derivatives
const textAtom = atom('hello')
const uppercaseAtom = atom(
(get) => get(textAtom).toUpperCase()
)
// Use them anywhere in your app
const Input = () => {
const [text, setText] = useAtom(textAtom)
const handleChange = (e) => setText(e.target.value)
return (
<input value={text} onChange={handleChange} />
)
}
const Uppercase = () => {
const [uppercase] = useAtom(uppercaseAtom)
return (
<div>Uppercase: {uppercase}</div>
)
}
// Now you have the components
const App = () => {
return (
<>
<Input />
<Uppercase />
</>
)
}

Extra utilities

The Jotai package also includes a jotai/utils bundle. These functions add support for persisting an atom’s state in localStorage (or URL hash), hydrating an atom’s state during server-side rendering, creating an atom with a set function including Redux-like reducers and action types, and much more!

import { useAtom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
// Set the string key and the initial value
const darkModeAtom = atomWithStorage('darkMode', false)
const Page = () => {
// Consume persisted state like any other atom
const [darkMode, setDarkMode] = useAtom(darkModeAtom)
const toggleDarkMode = () => setDarkMode(!darkMode)
return (
<>
<h1>Welcome to {darkMode ? 'dark' : 'light'} mode!</h1>
<button onClick={toggleDarkMode}>toggle theme</button>
</>
)
}

Third-party integrations

There are also additional bundles for each official third-party integration. Immer, Optics, Query, XState, Valtio, Zustand, Redux, and URQL.

Some integrations provide new atom types with alternate set functions such as atomWithImmer while others provide new atom types with two-way data binding with other state management libraries such as atomWithStore which is bound with a Redux store.

0
import { useAtom } from 'jotai'
import { atomWithImmer } from 'jotai/immer'
// Create a new atom with an immer-based write function
const countAtom = atomWithImmer(0)
const Counter = () => {
const [count] = useAtom(countAtom)
return (
<div>count: {count}</div>
)
}
const Controls = () => {
// setCount === update: (draft: Draft<Value>) => void
const [, setCount] = useAtom(countAtom)
const increment = () => setCount((c) => (c = c + 1))
return (
<button onClick={increment}>+1</button>
)
}

Learn more

Check out the free Egghead course by Daishi, the creator of Jotai.

Jotai course