Lazy
When defining primitive atoms, their initial value has to be bound at definition time. If creating that initial value is computationally expensive, or the value is not accessible during definition, it would be best to postpone the atom's initialization until its first use in the store.
const imageDataAtom = atom(initializeExpensiveImage()) // 1) has to be computed herefunction Home() {...}function ImageEditor() {// 2) used only in this routeconst [imageData, setImageData] = useAtom(imageDataAtom);...}function App() {return (<Router><Route path="/" component={Home} /><Route path="/edit" component={ImageEditor} /></Router>)}
atomWithLazy
Ref: https://github.com/pmndrs/jotai/pull/2465
We can use atomWithLazy
to create a primitive atom whose initial value will be computed at first use in the store.
After initialization, it will behave like a regular primitive atom (can be written to).
Usage
import { atomWithLazy } from 'jotai/utils'const imageDataAtom = atomWithLazy(() => initializeExpensiveImage())function Home() {...}function ImageEditor() {// only gets initialized if user goes to `/edit`.const [imageData, setImageData] = useAtom(imageDataAtom);...}function App() {return (<Router><Route path="/" component={Home} /><Route path="/edit" component={ImageEditor} /></Router>)}
Using multiple stores
Since each store is its separate universe, the initial value will be recreated exactly once per store (unless using something like jotai-scope
, which fractures a store into smaller universes).
type RGB = [number, number, number];function randomRGB(): RGB {...}const lift = (value: number) => ([r, g, b]: RGB) => {return [r + value, g + value, b + value]}const colorAtom = lazyAtom(randomRGB)let store = createStore();console.log(store.get(colorAtom)) // [0, 36, 128]store.set(colorAtom, lift(8))console.log(store.get(colorAtom)) // [8, 44, 136]// recreating store, sometimes done when logging out or resetting the app in some waystore = createStore();console.log(store.get(colorAtom)) // [255, 12, 46] -- a new random color