valtio-define 1.1.5 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.OLD.md +391 -0
- package/README.md +92 -248
- package/dist/index.d.mts +1 -1
- package/dist/plugins/persist/index.d.mts +1 -1
- package/dist/{types-BW_uQuTb.d.mts → types-CqDu3QIJ.d.mts} +4 -4
- package/package.json +1 -1
package/README.OLD.md
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# valtio-define
|
|
2
|
+
|
|
3
|
+
[![npm version][npm-version-src]][npm-version-href]
|
|
4
|
+
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
5
|
+
[![bundle][bundle-src]][bundle-href]
|
|
6
|
+
[![JSDocs][jsdocs-src]][jsdocs-href]
|
|
7
|
+
[![coverage][coverage-src]][coverage-href]
|
|
8
|
+
[![License][license-src]][license-href]
|
|
9
|
+
|
|
10
|
+
⚡ Quickly create a fully functional and robust [Valtio](https://valtio.dev) factory
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm add valtio-define
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Basic Store
|
|
21
|
+
|
|
22
|
+
Create a reactive store with state and actions. The store provides a simple and intuitive API for managing state in React applications, built on top of Valtio.
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { defineStore, useStore } from 'valtio-define'
|
|
26
|
+
|
|
27
|
+
const store = defineStore({
|
|
28
|
+
state: () => ({ count: 0 }),
|
|
29
|
+
actions: {
|
|
30
|
+
increment() {
|
|
31
|
+
this.count++
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
function Counter() {
|
|
37
|
+
const { count } = useStore(store)
|
|
38
|
+
return (
|
|
39
|
+
<div>
|
|
40
|
+
<button onClick={store.increment}>Increment</button>
|
|
41
|
+
<div>{count}</div>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### With Getters
|
|
48
|
+
|
|
49
|
+
Getters are computed properties that automatically update when their dependencies change. They provide a clean way to derive state without manually tracking dependencies.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
const store = defineStore({
|
|
53
|
+
state: () => ({ count: 0 }),
|
|
54
|
+
getters: {
|
|
55
|
+
doubled() {
|
|
56
|
+
return this.count * 2
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
actions: {
|
|
60
|
+
increment() {
|
|
61
|
+
this.count++
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
function Counter() {
|
|
67
|
+
const state = useStore(store)
|
|
68
|
+
return (
|
|
69
|
+
<div>
|
|
70
|
+
<div>
|
|
71
|
+
Count:
|
|
72
|
+
{state.count}
|
|
73
|
+
</div>
|
|
74
|
+
<div>
|
|
75
|
+
Doubled:
|
|
76
|
+
{state.doubled}
|
|
77
|
+
</div>
|
|
78
|
+
<button onClick={store.increment}>Increment</button>
|
|
79
|
+
</div>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Persistence
|
|
85
|
+
|
|
86
|
+
The persistence plugin allows you to persist store state to storage (e.g., localStorage).
|
|
87
|
+
|
|
88
|
+
First, register the persist plugin:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import valtio from 'valtio-define'
|
|
92
|
+
import { persist } from 'valtio-define/plugins'
|
|
93
|
+
|
|
94
|
+
// Register the persist plugin globally
|
|
95
|
+
valtio.use(persist())
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Then use it in your store:
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
import { defineStore } from 'valtio-define'
|
|
102
|
+
|
|
103
|
+
const store = defineStore({
|
|
104
|
+
state: () => ({ count: 0 }),
|
|
105
|
+
actions: {
|
|
106
|
+
increment() {
|
|
107
|
+
this.count++
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
persist: {
|
|
111
|
+
key: 'my-store',
|
|
112
|
+
storage: localStorage,
|
|
113
|
+
paths: ['count'], // Only persist 'count', or omit to persist all state
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
If `persist` is `true`, it will use `structure-id` to generate a unique key for the store automatically.
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
const store = defineStore({
|
|
122
|
+
state: () => ({ count: 0 }),
|
|
123
|
+
persist: true, // Auto-generates key using structure-id
|
|
124
|
+
})
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
You can pass `hydrate` when registering the plugin (default `true`). When `true`, state is hydrated from storage as soon as the store is created. Set `hydrate: false` when you need to avoid running persistence during server-side rendering, and manually mount persist in your App entry instead:
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
// Register with hydrate: false
|
|
131
|
+
store.use(persist({ hydrate: false }))
|
|
132
|
+
|
|
133
|
+
// In your App (client entry), after store is used:
|
|
134
|
+
useEffect(() => store.$persist.mount(), [])
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Subscribe to Changes
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
const store = defineStore({
|
|
141
|
+
state: () => ({ count: 0 }),
|
|
142
|
+
actions: {
|
|
143
|
+
increment() {
|
|
144
|
+
this.count++
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
// Subscribe to state changes
|
|
150
|
+
const unsubscribe = store.$subscribe((state) => {
|
|
151
|
+
console.log('State changed:', state)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
// Subscribe to specific key changes
|
|
155
|
+
const unsubscribeKey = store.$subscribeKey('count', (value) => {
|
|
156
|
+
console.log('Count changed:', value)
|
|
157
|
+
})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Patch State
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
// Patch with object
|
|
164
|
+
store.$patch({ count: 10 })
|
|
165
|
+
|
|
166
|
+
// Patch with function
|
|
167
|
+
store.$patch((state) => {
|
|
168
|
+
state.count += 5
|
|
169
|
+
})
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Signal (JSX Component)
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
function App() {
|
|
176
|
+
return (
|
|
177
|
+
<div>
|
|
178
|
+
Count:
|
|
179
|
+
{' '}
|
|
180
|
+
{store.$signal(state => state.count)}
|
|
181
|
+
</div>
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Store to State Hooks
|
|
187
|
+
|
|
188
|
+
Convert store state to React hooks similar to `useState`. This provides a more React-idiomatic way to access and update store state.
|
|
189
|
+
|
|
190
|
+
#### `storeToState(store, key)`
|
|
191
|
+
|
|
192
|
+
Returns a tuple `[state, setter]` for a single store key, similar to React's `useState`.
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
import { defineStore, storeToState } from 'valtio-define'
|
|
196
|
+
|
|
197
|
+
const store = defineStore({
|
|
198
|
+
state: { count: 0, name: 'test' },
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
function Counter() {
|
|
202
|
+
const [count, setCount] = storeToState(store, 'count')
|
|
203
|
+
const [name, setName] = storeToState(store, 'name')
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<div>
|
|
207
|
+
<button onClick={() => setCount(count + 1)}>Increment</button>
|
|
208
|
+
<button onClick={() => setCount(prev => prev + 1)}>Increment (functional)</button>
|
|
209
|
+
<div>
|
|
210
|
+
Count:
|
|
211
|
+
{count}
|
|
212
|
+
</div>
|
|
213
|
+
<div>
|
|
214
|
+
Name:
|
|
215
|
+
{name}
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Parameters:**
|
|
223
|
+
- `store`: Store instance created by `defineStore`
|
|
224
|
+
- `key`: Key of the state property to access
|
|
225
|
+
|
|
226
|
+
**Returns:** `[state, setter]` tuple where:
|
|
227
|
+
- `state`: Current value of the state property
|
|
228
|
+
- `setter`: Function to update the state (accepts value or updater function)
|
|
229
|
+
|
|
230
|
+
#### `storeToStates(store)`
|
|
231
|
+
|
|
232
|
+
Returns an object with all store keys mapped to `[state, setter]` tuples.
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
function Component() {
|
|
236
|
+
const {
|
|
237
|
+
count: [count, setCount],
|
|
238
|
+
name: [name, setName],
|
|
239
|
+
user: [user, setUser],
|
|
240
|
+
} = storeToStates(store)
|
|
241
|
+
|
|
242
|
+
return (
|
|
243
|
+
<div>
|
|
244
|
+
<button onClick={() => setCount(count + 1)}>Increment</button>
|
|
245
|
+
<div>
|
|
246
|
+
Count:
|
|
247
|
+
{count}
|
|
248
|
+
</div>
|
|
249
|
+
<div>
|
|
250
|
+
Name:
|
|
251
|
+
{name}
|
|
252
|
+
</div>
|
|
253
|
+
<div>
|
|
254
|
+
User:
|
|
255
|
+
{user.name}
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Parameters:**
|
|
263
|
+
- `store`: Store instance created by `defineStore`
|
|
264
|
+
|
|
265
|
+
**Returns:** Object where each key maps to a `[state, setter]` tuple
|
|
266
|
+
|
|
267
|
+
## API
|
|
268
|
+
|
|
269
|
+
### `defineStore(store)`
|
|
270
|
+
|
|
271
|
+
Creates a store with state, actions, and getters.
|
|
272
|
+
|
|
273
|
+
**Parameters:**
|
|
274
|
+
- `store.state`: Initial state object or factory function
|
|
275
|
+
- `store.actions`: Object containing action methods
|
|
276
|
+
- `store.getters`: Object containing getter methods
|
|
277
|
+
- `store.persist`: Persistence plugin configuration (boolean or object) - see [Persistence Plugin](#persistence)
|
|
278
|
+
|
|
279
|
+
**Returns:** Store instance with reactive state and actions
|
|
280
|
+
|
|
281
|
+
### `useStore(store)`
|
|
282
|
+
|
|
283
|
+
React hook that returns a snapshot of the store state.
|
|
284
|
+
|
|
285
|
+
**Parameters:**
|
|
286
|
+
- `store`: Store instance created by `defineStore`
|
|
287
|
+
|
|
288
|
+
**Returns:** Snapshot of the store state
|
|
289
|
+
|
|
290
|
+
### `storeToState(store, key)`
|
|
291
|
+
|
|
292
|
+
React hook that returns a `[state, setter]` tuple for a single store key, similar to React's `useState`.
|
|
293
|
+
|
|
294
|
+
**Parameters:**
|
|
295
|
+
- `store`: Store instance created by `defineStore`
|
|
296
|
+
- `key`: Key of the state property to access
|
|
297
|
+
|
|
298
|
+
**Returns:** `[state, setter]` tuple where:
|
|
299
|
+
- `state`: Current value of the state property
|
|
300
|
+
- `setter`: Function to update the state (accepts value or updater function like `setState(value)` or `setState(prev => newValue)`)
|
|
301
|
+
|
|
302
|
+
### `storeToStates(store)`
|
|
303
|
+
|
|
304
|
+
React hook that returns an object with all store keys mapped to `[state, setter]` tuples.
|
|
305
|
+
|
|
306
|
+
**Parameters:**
|
|
307
|
+
- `store`: Store instance created by `defineStore`
|
|
308
|
+
|
|
309
|
+
**Returns:** Object where each key maps to a `[state, setter]` tuple, preserving the correct type for each property
|
|
310
|
+
|
|
311
|
+
### Plugins
|
|
312
|
+
|
|
313
|
+
Plugins allow you to extend store functionality. You can use plugins globally or per-store.
|
|
314
|
+
|
|
315
|
+
#### Global Plugin Registration
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
import valtio from 'valtio-define'
|
|
319
|
+
import { persist } from 'valtio-define/plugins'
|
|
320
|
+
|
|
321
|
+
// Register plugin globally - applies to all stores
|
|
322
|
+
valtio.use(persist())
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
#### Per-Store Plugin Registration
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
import { defineStore } from 'valtio-define'
|
|
329
|
+
import { persist } from 'valtio-define/plugins'
|
|
330
|
+
|
|
331
|
+
const store = defineStore({
|
|
332
|
+
state: () => ({ count: 0 }),
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
// Register plugin for this specific store
|
|
336
|
+
store.use(persist())
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
#### Creating Custom Plugins
|
|
340
|
+
|
|
341
|
+
```tsx
|
|
342
|
+
import type { Plugin } from 'valtio-define'
|
|
343
|
+
|
|
344
|
+
function myPlugin() {
|
|
345
|
+
({ store, options }: PluginContext) => {
|
|
346
|
+
// Access store methods
|
|
347
|
+
store.$subscribe((state) => {
|
|
348
|
+
console.log('State changed:', state)
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
// Access store options
|
|
352
|
+
if (options.someOption) {
|
|
353
|
+
// Do something
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
declare module 'valtio-define' {
|
|
359
|
+
export interface StoreDefine<S extends object, A extends ActionsTree, G extends Getters<any>> {
|
|
360
|
+
myPlugin?: {
|
|
361
|
+
someOption?: boolean
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Use the plugin
|
|
367
|
+
use(myPlugin())
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Plugin Context:**
|
|
371
|
+
- `context.store`: The store instance with all methods (`$state`, `$patch`, `$subscribe`, etc.)
|
|
372
|
+
- `context.options`: The original store definition options
|
|
373
|
+
|
|
374
|
+
## License
|
|
375
|
+
|
|
376
|
+
[MIT](./LICENSE) License © [Hairyf](https://github.com/hairyf)
|
|
377
|
+
|
|
378
|
+
<!-- Badges -->
|
|
379
|
+
|
|
380
|
+
[npm-version-src]: https://img.shields.io/npm/v/valtio-define?style=flat&colorA=080f12&colorB=1fa669
|
|
381
|
+
[npm-version-href]: https://npmjs.com/package/valtio-define
|
|
382
|
+
[npm-downloads-src]: https://img.shields.io/npm/dm/valtio-define?style=flat&colorA=080f12&colorB=1fa669
|
|
383
|
+
[npm-downloads-href]: https://npmjs.com/package/valtio-define
|
|
384
|
+
[bundle-src]: https://img.shields.io/bundlephobia/minzip/valtio-define?style=flat&colorA=080f12&colorB=1fa669&label=minzip
|
|
385
|
+
[bundle-href]: https://bundlephobia.com/result?p=valtio-define
|
|
386
|
+
[license-src]: https://img.shields.io/github/license/hairyf/valtio-define.svg?style=flat&colorA=080f12&colorB=1fa669
|
|
387
|
+
[license-href]: https://github.com/hairyf/valtio-define/blob/main/LICENSE
|
|
388
|
+
[jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-080f12?style=flat&colorA=080f12&colorB=1fa669
|
|
389
|
+
[jsdocs-href]: https://www.jsdocs.io/package/valtio-define
|
|
390
|
+
[coverage-src]: https://codecov.io/gh/hairyf/valtio-define/graph/badge.svg?token=PG5YIEEEHJ
|
|
391
|
+
[coverage-href]: https://codecov.io/gh/hairyf/valtio-define
|
package/README.md
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+

|
|
2
2
|
|
|
3
3
|
[![npm version][npm-version-src]][npm-version-href]
|
|
4
4
|
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
5
5
|
[![bundle][bundle-src]][bundle-href]
|
|
6
6
|
[![JSDocs][jsdocs-src]][jsdocs-href]
|
|
7
7
|
[![coverage][coverage-src]][coverage-href]
|
|
8
|
-
[![License][license-src]][license-href]
|
|
8
|
+
[![License][license-src]][license-href].
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
⚡️ **valtio-define** is a lightweight factory for creating fully functional, robust [Valtio](https://valtio.dev) stores. It simplifies state management in React by providing a structured API for state, actions, and computed getters.
|
|
11
11
|
|
|
12
|
-
## Installation
|
|
12
|
+
## 📦 Installation
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
15
|
pnpm add valtio-define
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## 🚀 Quick Start
|
|
19
19
|
|
|
20
20
|
### Basic Store
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
`defineStore` allows you to encapsulate state and logic in one place. Use `useStore` to consume the reactive state in your components.
|
|
23
23
|
|
|
24
24
|
```tsx
|
|
25
25
|
import { defineStore, useStore } from 'valtio-define'
|
|
@@ -28,6 +28,7 @@ const store = defineStore({
|
|
|
28
28
|
state: () => ({ count: 0 }),
|
|
29
29
|
actions: {
|
|
30
30
|
increment() {
|
|
31
|
+
// 'this' refers to the reactive state
|
|
31
32
|
this.count++
|
|
32
33
|
},
|
|
33
34
|
},
|
|
@@ -35,18 +36,22 @@ const store = defineStore({
|
|
|
35
36
|
|
|
36
37
|
function Counter() {
|
|
37
38
|
const { count } = useStore(store)
|
|
39
|
+
|
|
38
40
|
return (
|
|
39
41
|
<div>
|
|
42
|
+
<div>
|
|
43
|
+
Count:
|
|
44
|
+
{count}
|
|
45
|
+
</div>
|
|
40
46
|
<button onClick={store.increment}>Increment</button>
|
|
41
|
-
<div>{count}</div>
|
|
42
47
|
</div>
|
|
43
48
|
)
|
|
44
49
|
}
|
|
45
50
|
```
|
|
46
51
|
|
|
47
|
-
###
|
|
52
|
+
### Derived State (Getters)
|
|
48
53
|
|
|
49
|
-
Getters are computed properties
|
|
54
|
+
Getters are **computed properties**. They automatically re-evaluate when their dependencies change, providing a clean way to derive data.
|
|
50
55
|
|
|
51
56
|
```tsx
|
|
52
57
|
const store = defineStore({
|
|
@@ -62,314 +67,153 @@ const store = defineStore({
|
|
|
62
67
|
},
|
|
63
68
|
},
|
|
64
69
|
})
|
|
65
|
-
|
|
66
|
-
function Counter() {
|
|
67
|
-
const state = useStore(store)
|
|
68
|
-
return (
|
|
69
|
-
<div>
|
|
70
|
-
<div>
|
|
71
|
-
Count:
|
|
72
|
-
{state.count}
|
|
73
|
-
</div>
|
|
74
|
-
<div>
|
|
75
|
-
Doubled:
|
|
76
|
-
{state.doubled}
|
|
77
|
-
</div>
|
|
78
|
-
<button onClick={store.increment}>Increment</button>
|
|
79
|
-
</div>
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
70
|
```
|
|
83
71
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
The persistence plugin allows you to persist store state to storage (e.g., localStorage).
|
|
72
|
+
-----
|
|
87
73
|
|
|
88
|
-
|
|
74
|
+
## 🛠 Advanced Features
|
|
89
75
|
|
|
90
|
-
|
|
91
|
-
import valtio from 'valtio-define'
|
|
92
|
-
import { persist } from 'valtio-define/plugins'
|
|
93
|
-
|
|
94
|
-
// Register the persist plugin globally
|
|
95
|
-
valtio.use(persist())
|
|
96
|
-
```
|
|
76
|
+
### The Power of `this`
|
|
97
77
|
|
|
98
|
-
|
|
78
|
+
Inside `actions` and `getters`, `this` provides full access to the store's state, other actions, and other getters. This type safety across the entire store.
|
|
99
79
|
|
|
100
80
|
```tsx
|
|
101
|
-
import { defineStore } from 'valtio-define'
|
|
102
|
-
|
|
103
81
|
const store = defineStore({
|
|
104
|
-
state: () => ({
|
|
82
|
+
state: () => ({
|
|
83
|
+
count: 0,
|
|
84
|
+
}),
|
|
105
85
|
actions: {
|
|
106
|
-
|
|
107
|
-
|
|
86
|
+
// Autocompletion and typings for the whole store ✨
|
|
87
|
+
currentDoubledOne() {
|
|
88
|
+
return this.doublePlusOne
|
|
108
89
|
},
|
|
109
90
|
},
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
91
|
+
getters: {
|
|
92
|
+
doubled() {
|
|
93
|
+
return this.count * 2
|
|
94
|
+
},
|
|
95
|
+
// Note: The return type **must** be explicitly set for complex getters
|
|
96
|
+
doublePlusOne() {
|
|
97
|
+
// Access other getters via 'this'
|
|
98
|
+
return this.doubled + 1
|
|
99
|
+
},
|
|
114
100
|
},
|
|
115
101
|
})
|
|
116
102
|
```
|
|
117
103
|
|
|
118
|
-
|
|
104
|
+
### Persistence
|
|
119
105
|
|
|
120
|
-
|
|
121
|
-
const store = defineStore({
|
|
122
|
-
state: () => ({ count: 0 }),
|
|
123
|
-
persist: true, // Auto-generates key using structure-id
|
|
124
|
-
})
|
|
125
|
-
```
|
|
106
|
+
Save and restore your store state using the `persist` plugin.
|
|
126
107
|
|
|
127
|
-
|
|
108
|
+
1. **Global Registration:**
|
|
128
109
|
|
|
129
|
-
```tsx
|
|
130
|
-
|
|
131
|
-
|
|
110
|
+
```tsx
|
|
111
|
+
import valtio from 'valtio-define'
|
|
112
|
+
import { persist } from 'valtio-define/plugins'
|
|
132
113
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
```
|
|
114
|
+
valtio.use(persist())
|
|
115
|
+
```
|
|
136
116
|
|
|
137
|
-
|
|
117
|
+
2. **Store Configuration:**
|
|
138
118
|
|
|
139
|
-
```tsx
|
|
140
|
-
const store = defineStore({
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
})
|
|
119
|
+
```tsx
|
|
120
|
+
const store = defineStore({
|
|
121
|
+
state: () => ({ count: 0 }),
|
|
122
|
+
persist: {
|
|
123
|
+
key: 'my-app-storage',
|
|
124
|
+
storage: localStorage,
|
|
125
|
+
paths: ['count'], // Optional: Persist specific keys only
|
|
126
|
+
},
|
|
127
|
+
})
|
|
128
|
+
```
|
|
148
129
|
|
|
149
|
-
|
|
150
|
-
const unsubscribe = store.$subscribe((state) => {
|
|
151
|
-
console.log('State changed:', state)
|
|
152
|
-
})
|
|
130
|
+
> **Tip:** If you set `persist: true`, a unique key is automatically generated using `structure-id`.
|
|
153
131
|
|
|
154
|
-
|
|
155
|
-
const unsubscribeKey = store.$subscribeKey('count', (value) => {
|
|
156
|
-
console.log('Count changed:', value)
|
|
157
|
-
})
|
|
158
|
-
```
|
|
132
|
+
### Manual Hydration (SSR Friendly)
|
|
159
133
|
|
|
160
|
-
|
|
134
|
+
To avoid hydration mismatches during Server-Side Rendering, disable automatic hydration and mount it in a `useEffect`.
|
|
161
135
|
|
|
162
136
|
```tsx
|
|
163
|
-
//
|
|
164
|
-
store
|
|
137
|
+
// Register with hydrate disabled
|
|
138
|
+
store.use(persist({ hydrate: false }))
|
|
165
139
|
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
})
|
|
140
|
+
// In your Client Entry / App Root
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
store.$persist.mount()
|
|
143
|
+
}, [])
|
|
170
144
|
```
|
|
171
145
|
|
|
172
|
-
###
|
|
173
|
-
|
|
174
|
-
```tsx
|
|
175
|
-
function App() {
|
|
176
|
-
return (
|
|
177
|
-
<div>
|
|
178
|
-
Count:
|
|
179
|
-
{' '}
|
|
180
|
-
{store.$signal(state => state.count)}
|
|
181
|
-
</div>
|
|
182
|
-
)
|
|
183
|
-
}
|
|
184
|
-
```
|
|
146
|
+
### React-Idiomatic State Hooks
|
|
185
147
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
Convert store state to React hooks similar to `useState`. This provides a more React-idiomatic way to access and update store state.
|
|
189
|
-
|
|
190
|
-
#### `storeToState(store, key)`
|
|
191
|
-
|
|
192
|
-
Returns a tuple `[state, setter]` for a single store key, similar to React's `useState`.
|
|
148
|
+
If you prefer the `useState` syntax, use `storeToState` or `storeToStates`. These return `[state, setter]` tuples.
|
|
193
149
|
|
|
194
150
|
```tsx
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const store = defineStore({
|
|
198
|
-
state: { count: 0, name: 'test' },
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
function Counter() {
|
|
202
|
-
const [count, setCount] = storeToState(store, 'count')
|
|
151
|
+
function Profile() {
|
|
152
|
+
// Access a single key
|
|
203
153
|
const [name, setName] = storeToState(store, 'name')
|
|
204
154
|
|
|
205
|
-
|
|
206
|
-
<div>
|
|
207
|
-
<button onClick={() => setCount(count + 1)}>Increment</button>
|
|
208
|
-
<button onClick={() => setCount(prev => prev + 1)}>Increment (functional)</button>
|
|
209
|
-
<div>
|
|
210
|
-
Count:
|
|
211
|
-
{count}
|
|
212
|
-
</div>
|
|
213
|
-
<div>
|
|
214
|
-
Name:
|
|
215
|
-
{name}
|
|
216
|
-
</div>
|
|
217
|
-
</div>
|
|
218
|
-
)
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
**Parameters:**
|
|
223
|
-
- `store`: Store instance created by `defineStore`
|
|
224
|
-
- `key`: Key of the state property to access
|
|
225
|
-
|
|
226
|
-
**Returns:** `[state, setter]` tuple where:
|
|
227
|
-
- `state`: Current value of the state property
|
|
228
|
-
- `setter`: Function to update the state (accepts value or updater function)
|
|
229
|
-
|
|
230
|
-
#### `storeToStates(store)`
|
|
231
|
-
|
|
232
|
-
Returns an object with all store keys mapped to `[state, setter]` tuples.
|
|
233
|
-
|
|
234
|
-
```tsx
|
|
235
|
-
function Component() {
|
|
155
|
+
// Access all keys as hooks
|
|
236
156
|
const {
|
|
237
|
-
count: [count, setCount]
|
|
238
|
-
name: [name, setName],
|
|
239
|
-
user: [user, setUser],
|
|
157
|
+
count: [count, setCount]
|
|
240
158
|
} = storeToStates(store)
|
|
241
159
|
|
|
242
|
-
return (
|
|
243
|
-
<div>
|
|
244
|
-
<button onClick={() => setCount(count + 1)}>Increment</button>
|
|
245
|
-
<div>
|
|
246
|
-
Count:
|
|
247
|
-
{count}
|
|
248
|
-
</div>
|
|
249
|
-
<div>
|
|
250
|
-
Name:
|
|
251
|
-
{name}
|
|
252
|
-
</div>
|
|
253
|
-
<div>
|
|
254
|
-
User:
|
|
255
|
-
{user.name}
|
|
256
|
-
</div>
|
|
257
|
-
</div>
|
|
258
|
-
)
|
|
160
|
+
return <input value={name} onChange={e => setName(e.target.value)} />
|
|
259
161
|
}
|
|
260
162
|
```
|
|
261
163
|
|
|
262
|
-
|
|
263
|
-
- `store`: Store instance created by `defineStore`
|
|
264
|
-
|
|
265
|
-
**Returns:** Object where each key maps to a `[state, setter]` tuple
|
|
266
|
-
|
|
267
|
-
## API
|
|
268
|
-
|
|
269
|
-
### `defineStore(store)`
|
|
270
|
-
|
|
271
|
-
Creates a store with state, actions, and getters.
|
|
272
|
-
|
|
273
|
-
**Parameters:**
|
|
274
|
-
- `store.state`: Initial state object or factory function
|
|
275
|
-
- `store.actions`: Object containing action methods
|
|
276
|
-
- `store.getters`: Object containing getter methods
|
|
277
|
-
- `store.persist`: Persistence plugin configuration (boolean or object) - see [Persistence Plugin](#persistence)
|
|
278
|
-
|
|
279
|
-
**Returns:** Store instance with reactive state and actions
|
|
280
|
-
|
|
281
|
-
### `useStore(store)`
|
|
282
|
-
|
|
283
|
-
React hook that returns a snapshot of the store state.
|
|
284
|
-
|
|
285
|
-
**Parameters:**
|
|
286
|
-
- `store`: Store instance created by `defineStore`
|
|
287
|
-
|
|
288
|
-
**Returns:** Snapshot of the store state
|
|
164
|
+
-----
|
|
289
165
|
|
|
290
|
-
|
|
166
|
+
## 🛰 Store API
|
|
291
167
|
|
|
292
|
-
|
|
168
|
+
Every store instance created with `defineStore` includes built-in utility methods:
|
|
293
169
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
170
|
+
* **`$patch(obj | fn)`**: Bulk update the state.
|
|
171
|
+
* **`$subscribe(callback)`**: Watch the entire store for changes.
|
|
172
|
+
* **`$subscribeKey(key, callback)`**: Watch a specific property.
|
|
173
|
+
* **`$signal(selector)`**: Use a selector function inside JSX for fine-grained reactivity.
|
|
297
174
|
|
|
298
|
-
|
|
299
|
-
- `state`: Current value of the state property
|
|
300
|
-
- `setter`: Function to update the state (accepts value or updater function like `setState(value)` or `setState(prev => newValue)`)
|
|
175
|
+
-----
|
|
301
176
|
|
|
302
|
-
|
|
177
|
+
## 🔌 Plugins
|
|
303
178
|
|
|
304
|
-
|
|
179
|
+
### Global vs. Per-Store
|
|
305
180
|
|
|
306
|
-
|
|
307
|
-
- `store`: Store instance created by `defineStore`
|
|
308
|
-
|
|
309
|
-
**Returns:** Object where each key maps to a `[state, setter]` tuple, preserving the correct type for each property
|
|
310
|
-
|
|
311
|
-
### Plugins
|
|
312
|
-
|
|
313
|
-
Plugins allow you to extend store functionality. You can use plugins globally or per-store.
|
|
314
|
-
|
|
315
|
-
#### Global Plugin Registration
|
|
181
|
+
Plugins can be applied to all stores or restricted to a single instance.
|
|
316
182
|
|
|
317
183
|
```tsx
|
|
318
|
-
|
|
319
|
-
|
|
184
|
+
// Global
|
|
185
|
+
valtio.use(myPlugin())
|
|
320
186
|
|
|
321
|
-
//
|
|
322
|
-
|
|
187
|
+
// Local
|
|
188
|
+
const store = defineStore({ /* ... */ })
|
|
189
|
+
store.use(myPlugin())
|
|
323
190
|
```
|
|
324
191
|
|
|
325
|
-
|
|
192
|
+
### Creating a Custom Plugin
|
|
326
193
|
|
|
327
|
-
|
|
328
|
-
import { defineStore } from 'valtio-define'
|
|
329
|
-
import { persist } from 'valtio-define/plugins'
|
|
330
|
-
|
|
331
|
-
const store = defineStore({
|
|
332
|
-
state: () => ({ count: 0 }),
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
// Register plugin for this specific store
|
|
336
|
-
store.use(persist())
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
#### Creating Custom Plugins
|
|
194
|
+
Extend functionality by accessing the `store` instance and `options` through the plugin context.
|
|
340
195
|
|
|
341
196
|
```tsx
|
|
342
197
|
import type { Plugin } from 'valtio-define'
|
|
343
198
|
|
|
344
|
-
function
|
|
345
|
-
({ store, options }
|
|
346
|
-
// Access store methods
|
|
199
|
+
function loggerPlugin(): Plugin {
|
|
200
|
+
return ({ store, options }) => {
|
|
347
201
|
store.$subscribe((state) => {
|
|
348
|
-
console.log('
|
|
202
|
+
console.log('Update:', state)
|
|
349
203
|
})
|
|
350
|
-
|
|
351
|
-
// Access store options
|
|
352
|
-
if (options.someOption) {
|
|
353
|
-
// Do something
|
|
354
|
-
}
|
|
355
204
|
}
|
|
356
205
|
}
|
|
357
206
|
|
|
358
207
|
declare module 'valtio-define' {
|
|
359
|
-
export interface
|
|
360
|
-
myPlugin?: {
|
|
208
|
+
export interface StoreDefineOptions<S extends object> {
|
|
209
|
+
$myPlugin?: {
|
|
361
210
|
someOption?: boolean
|
|
362
211
|
}
|
|
363
212
|
}
|
|
364
213
|
}
|
|
365
|
-
|
|
366
|
-
// Use the plugin
|
|
367
|
-
use(myPlugin())
|
|
368
214
|
```
|
|
369
215
|
|
|
370
|
-
|
|
371
|
-
- `context.store`: The store instance with all methods (`$state`, `$patch`, `$subscribe`, etc.)
|
|
372
|
-
- `context.options`: The original store definition options
|
|
216
|
+
-----
|
|
373
217
|
|
|
374
218
|
## License
|
|
375
219
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as GettersReturnType, c as PluginContext, d as StoreDefine, f as StoreDefineOptions, h as SubscribeKey, i as Getters, l as Signal, m as Subscribe, n as ActionsOmitThisParameter, o as Patch, p as StoreOptions, r as ActionsTree, s as Plugin, t as Actions, u as Store } from "./types-
|
|
1
|
+
import { a as GettersReturnType, c as PluginContext, d as StoreDefine, f as StoreDefineOptions, h as SubscribeKey, i as Getters, l as Signal, m as Subscribe, n as ActionsOmitThisParameter, o as Patch, p as StoreOptions, r as ActionsTree, s as Plugin, t as Actions, u as Store } from "./types-CqDu3QIJ.mjs";
|
|
2
2
|
import { Snapshot } from "valtio";
|
|
3
3
|
import { Dispatch, SetStateAction } from "react";
|
|
4
4
|
|
|
@@ -7,10 +7,10 @@ type Getters<S = any> = Record<string, (this: S) => any>;
|
|
|
7
7
|
type ActionsOmitThisParameter<A extends Actions<any>> = { [K in keyof A]: (...args: Parameters<A[K]>) => ReturnType<A[K]> };
|
|
8
8
|
type GettersReturnType<G extends Getters<any>> = { [K in keyof G]: ReturnType<G[K]> };
|
|
9
9
|
interface StoreDefineOptions<S> {}
|
|
10
|
-
interface StoreDefine<S extends object, A, G extends Getters<any>> extends StoreDefineOptions<S> {
|
|
10
|
+
interface StoreDefine<S extends object, A extends object, G extends Getters<any>> extends StoreDefineOptions<S> {
|
|
11
11
|
state: (() => S) | S;
|
|
12
|
-
actions?: A & ThisType<A & S
|
|
13
|
-
getters?: G & ThisType<S
|
|
12
|
+
actions?: A & ThisType<A & S & GettersReturnType<G>>;
|
|
13
|
+
getters?: G & ThisType<S & GettersReturnType<G>>;
|
|
14
14
|
}
|
|
15
15
|
interface Signal<S, G extends Getters<S>> {
|
|
16
16
|
<T>(fn: (state: S & GettersReturnType<G>) => T): ReactElement;
|
|
@@ -27,7 +27,7 @@ interface Patch<S, G extends Getters<S>> {
|
|
|
27
27
|
(patch: Partial<S> | ((state: S & GettersReturnType<G>) => void)): void;
|
|
28
28
|
}
|
|
29
29
|
interface StoreOptions {}
|
|
30
|
-
type Store<S, A extends Actions<S
|
|
30
|
+
type Store<S, A extends Actions<S> = {}, G extends Getters<S> = {}> = {
|
|
31
31
|
$subscribe: Subscribe<S, G>;
|
|
32
32
|
$subscribeKey: SubscribeKey<S, G>;
|
|
33
33
|
$patch: Patch<S, G>;
|
package/package.json
CHANGED