|
| 1 | +--- |
| 2 | +title: Lazy |
| 3 | +nav: 3.03 |
| 4 | +keywords: lazy,initialize,init,loading |
| 5 | +--- |
| 6 | + |
| 7 | +When defining primitive atoms, their initial value has to be bound at definition time. |
| 8 | +If creating that initial value is computationally expensive, or the value is not accessible during definition, |
| 9 | +it would be best to postpone the atom's initialization until its [first use in the store](#using-multiple-stores). |
| 10 | + |
| 11 | +```jsx |
| 12 | +const imageDataAtom = atom(initializeExpensiveImage()) // 1) has to be computed here |
| 13 | + |
| 14 | +function Home() { |
| 15 | + ... |
| 16 | +} |
| 17 | + |
| 18 | +function ImageEditor() { |
| 19 | + // 2) used only in this route |
| 20 | + const [imageData, setImageData] = useAtom(imageDataAtom); |
| 21 | + ... |
| 22 | +} |
| 23 | + |
| 24 | +function App() { |
| 25 | + return ( |
| 26 | + <Router> |
| 27 | + <Route path="/" component={Home} /> |
| 28 | + <Route path="/edit" component={ImageEditor} /> |
| 29 | + </Router> |
| 30 | + ) |
| 31 | +} |
| 32 | +``` |
| 33 | + |
| 34 | +## atomWithLazy |
| 35 | + |
| 36 | +Ref: https://github.com/pmndrs/jotai/pull/2465 |
| 37 | + |
| 38 | +We can use `atomWithLazy` to create a primitive atom whose initial value will be computed at [first use in the store](#using-multiple-stores). |
| 39 | +After initialization, it will behave like a regular primitive atom (can be written to). |
| 40 | + |
| 41 | +### Usage |
| 42 | + |
| 43 | +```jsx |
| 44 | +import { atomWithLazy } from 'jotai/utils' |
| 45 | + |
| 46 | +// passing the initialization function |
| 47 | +const imageDataAtom = atomWithLazy(initializeExpensiveImage) |
| 48 | + |
| 49 | +function Home() { |
| 50 | + ... |
| 51 | +} |
| 52 | + |
| 53 | +function ImageEditor() { |
| 54 | + // only gets initialized if user goes to `/edit`. |
| 55 | + const [imageData, setImageData] = useAtom(imageDataAtom); |
| 56 | + ... |
| 57 | +} |
| 58 | + |
| 59 | +function App() { |
| 60 | + return ( |
| 61 | + <Router> |
| 62 | + <Route path="/" component={Home} /> |
| 63 | + <Route path="/edit" component={ImageEditor} /> |
| 64 | + </Router> |
| 65 | + ) |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | +### Using multiple stores |
| 70 | + |
| 71 | +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). |
| 72 | + |
| 73 | +```ts |
| 74 | +type RGB = [number, number, number]; |
| 75 | + |
| 76 | +function randomRGB(): RGB { |
| 77 | + ... |
| 78 | +} |
| 79 | + |
| 80 | +const lift = (value: number) => ([r, g, b]: RGB) => { |
| 81 | + return [r + value, g + value, b + value] |
| 82 | +} |
| 83 | + |
| 84 | +const colorAtom = lazyAtom(randomRGB) |
| 85 | + |
| 86 | +let store = createStore() |
| 87 | + |
| 88 | +console.log(store.get(colorAtom)) // [0, 36, 128] |
| 89 | +store.set(colorAtom, lift(8)) |
| 90 | +console.log(store.get(colorAtom)) // [8, 44, 136] |
| 91 | + |
| 92 | +// recreating store, sometimes done when logging out or resetting the app in some way |
| 93 | +store = createStore() |
| 94 | + |
| 95 | +console.log(store.get(colorAtom)) // [255, 12, 46] -- a new random color |
| 96 | +``` |
0 commit comments