@usefy/use-local-storage 0.0.17 → 0.0.18
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.md +73 -66
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,16 +84,16 @@ This package requires React 18 or 19:
|
|
|
84
84
|
## Quick Start
|
|
85
85
|
|
|
86
86
|
```tsx
|
|
87
|
-
import { useLocalStorage } from
|
|
87
|
+
import { useLocalStorage } from "@usefy/use-local-storage";
|
|
88
88
|
|
|
89
89
|
function ThemeToggle() {
|
|
90
|
-
const [theme, setTheme, removeTheme] = useLocalStorage(
|
|
90
|
+
const [theme, setTheme, removeTheme] = useLocalStorage("theme", "light");
|
|
91
91
|
|
|
92
92
|
return (
|
|
93
93
|
<div>
|
|
94
94
|
<p>Current theme: {theme}</p>
|
|
95
|
-
<button onClick={() => setTheme(
|
|
96
|
-
<button onClick={() => setTheme(
|
|
95
|
+
<button onClick={() => setTheme("dark")}>Dark</button>
|
|
96
|
+
<button onClick={() => setTheme("light")}>Light</button>
|
|
97
97
|
<button onClick={removeTheme}>Reset</button>
|
|
98
98
|
</div>
|
|
99
99
|
);
|
|
@@ -110,28 +110,28 @@ A hook that persists state in localStorage with automatic synchronization.
|
|
|
110
110
|
|
|
111
111
|
#### Parameters
|
|
112
112
|
|
|
113
|
-
| Parameter
|
|
114
|
-
|
|
115
|
-
| `key`
|
|
116
|
-
| `initialValue` | `T \| () => T`
|
|
117
|
-
| `options`
|
|
113
|
+
| Parameter | Type | Description |
|
|
114
|
+
| -------------- | --------------------------- | ------------------------------------------ |
|
|
115
|
+
| `key` | `string` | The localStorage key |
|
|
116
|
+
| `initialValue` | `T \| () => T` | Initial value or lazy initializer function |
|
|
117
|
+
| `options` | `UseLocalStorageOptions<T>` | Configuration options |
|
|
118
118
|
|
|
119
119
|
#### Options
|
|
120
120
|
|
|
121
|
-
| Option
|
|
122
|
-
|
|
123
|
-
| `serializer`
|
|
124
|
-
| `deserializer` | `(value: string) => T`
|
|
125
|
-
| `syncTabs`
|
|
126
|
-
| `onError`
|
|
121
|
+
| Option | Type | Default | Description |
|
|
122
|
+
| -------------- | ------------------------ | ---------------- | ------------------------------ |
|
|
123
|
+
| `serializer` | `(value: T) => string` | `JSON.stringify` | Custom serializer function |
|
|
124
|
+
| `deserializer` | `(value: string) => T` | `JSON.parse` | Custom deserializer function |
|
|
125
|
+
| `syncTabs` | `boolean` | `true` | Sync value across browser tabs |
|
|
126
|
+
| `onError` | `(error: Error) => void` | — | Callback for error handling |
|
|
127
127
|
|
|
128
128
|
#### Returns `[T, SetValue<T>, RemoveValue]`
|
|
129
129
|
|
|
130
|
-
| Index | Type
|
|
131
|
-
|
|
132
|
-
| `[0]` | `T`
|
|
133
|
-
| `[1]` | `Dispatch<SetStateAction<T>>` | Function to update value (same as useState)
|
|
134
|
-
| `[2]` | `() => void`
|
|
130
|
+
| Index | Type | Description |
|
|
131
|
+
| ----- | ----------------------------- | --------------------------------------------- |
|
|
132
|
+
| `[0]` | `T` | Current stored value |
|
|
133
|
+
| `[1]` | `Dispatch<SetStateAction<T>>` | Function to update value (same as useState) |
|
|
134
|
+
| `[2]` | `() => void` | Function to remove value and reset to initial |
|
|
135
135
|
|
|
136
136
|
---
|
|
137
137
|
|
|
@@ -140,10 +140,10 @@ A hook that persists state in localStorage with automatic synchronization.
|
|
|
140
140
|
### Basic String Storage
|
|
141
141
|
|
|
142
142
|
```tsx
|
|
143
|
-
import { useLocalStorage } from
|
|
143
|
+
import { useLocalStorage } from "@usefy/use-local-storage";
|
|
144
144
|
|
|
145
145
|
function NameInput() {
|
|
146
|
-
const [name, setName, removeName] = useLocalStorage(
|
|
146
|
+
const [name, setName, removeName] = useLocalStorage("userName", "");
|
|
147
147
|
|
|
148
148
|
return (
|
|
149
149
|
<div>
|
|
@@ -153,7 +153,7 @@ function NameInput() {
|
|
|
153
153
|
placeholder="Enter your name"
|
|
154
154
|
/>
|
|
155
155
|
<button onClick={removeName}>Clear</button>
|
|
156
|
-
<p>Hello, {name ||
|
|
156
|
+
<p>Hello, {name || "Guest"}!</p>
|
|
157
157
|
</div>
|
|
158
158
|
);
|
|
159
159
|
}
|
|
@@ -162,7 +162,7 @@ function NameInput() {
|
|
|
162
162
|
### Object State
|
|
163
163
|
|
|
164
164
|
```tsx
|
|
165
|
-
import { useLocalStorage } from
|
|
165
|
+
import { useLocalStorage } from "@usefy/use-local-storage";
|
|
166
166
|
|
|
167
167
|
interface UserSettings {
|
|
168
168
|
notifications: boolean;
|
|
@@ -171,9 +171,9 @@ interface UserSettings {
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
function SettingsPanel() {
|
|
174
|
-
const [settings, setSettings] = useLocalStorage<UserSettings>(
|
|
174
|
+
const [settings, setSettings] = useLocalStorage<UserSettings>("settings", {
|
|
175
175
|
notifications: true,
|
|
176
|
-
language:
|
|
176
|
+
language: "en",
|
|
177
177
|
fontSize: 16,
|
|
178
178
|
});
|
|
179
179
|
|
|
@@ -184,7 +184,10 @@ function SettingsPanel() {
|
|
|
184
184
|
type="checkbox"
|
|
185
185
|
checked={settings.notifications}
|
|
186
186
|
onChange={(e) =>
|
|
187
|
-
setSettings((prev) => ({
|
|
187
|
+
setSettings((prev) => ({
|
|
188
|
+
...prev,
|
|
189
|
+
notifications: e.target.checked,
|
|
190
|
+
}))
|
|
188
191
|
}
|
|
189
192
|
/>
|
|
190
193
|
Enable Notifications
|
|
@@ -218,12 +221,12 @@ function SettingsPanel() {
|
|
|
218
221
|
### Lazy Initialization
|
|
219
222
|
|
|
220
223
|
```tsx
|
|
221
|
-
import { useLocalStorage } from
|
|
224
|
+
import { useLocalStorage } from "@usefy/use-local-storage";
|
|
222
225
|
|
|
223
226
|
function ExpensiveDefaultDemo() {
|
|
224
227
|
// Expensive computation only runs if no stored value exists
|
|
225
|
-
const [config, setConfig] = useLocalStorage(
|
|
226
|
-
console.log(
|
|
228
|
+
const [config, setConfig] = useLocalStorage("appConfig", () => {
|
|
229
|
+
console.log("Computing expensive default...");
|
|
227
230
|
return generateComplexDefaultConfig();
|
|
228
231
|
});
|
|
229
232
|
|
|
@@ -234,11 +237,11 @@ function ExpensiveDefaultDemo() {
|
|
|
234
237
|
### Custom Serialization (Date)
|
|
235
238
|
|
|
236
239
|
```tsx
|
|
237
|
-
import { useLocalStorage } from
|
|
240
|
+
import { useLocalStorage } from "@usefy/use-local-storage";
|
|
238
241
|
|
|
239
242
|
function DatePicker() {
|
|
240
243
|
const [lastVisit, setLastVisit] = useLocalStorage<Date>(
|
|
241
|
-
|
|
244
|
+
"lastVisit",
|
|
242
245
|
new Date(),
|
|
243
246
|
{
|
|
244
247
|
serializer: (date) => date.toISOString(),
|
|
@@ -258,11 +261,11 @@ function DatePicker() {
|
|
|
258
261
|
### Custom Serialization (Map)
|
|
259
262
|
|
|
260
263
|
```tsx
|
|
261
|
-
import { useLocalStorage } from
|
|
264
|
+
import { useLocalStorage } from "@usefy/use-local-storage";
|
|
262
265
|
|
|
263
266
|
function FavoritesManager() {
|
|
264
267
|
const [favorites, setFavorites] = useLocalStorage<Map<string, boolean>>(
|
|
265
|
-
|
|
268
|
+
"favorites",
|
|
266
269
|
new Map(),
|
|
267
270
|
{
|
|
268
271
|
serializer: (map) => JSON.stringify([...map.entries()]),
|
|
@@ -284,7 +287,7 @@ function FavoritesManager() {
|
|
|
284
287
|
<li key={item.id}>
|
|
285
288
|
{item.name}
|
|
286
289
|
<button onClick={() => toggleFavorite(item.id)}>
|
|
287
|
-
{favorites.has(item.id) ?
|
|
290
|
+
{favorites.has(item.id) ? "★" : "☆"}
|
|
288
291
|
</button>
|
|
289
292
|
</li>
|
|
290
293
|
))}
|
|
@@ -296,16 +299,20 @@ function FavoritesManager() {
|
|
|
296
299
|
### Error Handling
|
|
297
300
|
|
|
298
301
|
```tsx
|
|
299
|
-
import { useLocalStorage } from
|
|
302
|
+
import { useLocalStorage } from "@usefy/use-local-storage";
|
|
300
303
|
|
|
301
304
|
function RobustStorage() {
|
|
302
|
-
const [data, setData] = useLocalStorage(
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
305
|
+
const [data, setData] = useLocalStorage(
|
|
306
|
+
"userData",
|
|
307
|
+
{ items: [] },
|
|
308
|
+
{
|
|
309
|
+
onError: (error) => {
|
|
310
|
+
console.error("Storage error:", error.message);
|
|
311
|
+
// Could show toast notification, log to analytics, etc.
|
|
312
|
+
toast.error("Failed to save data. Storage may be full.");
|
|
313
|
+
},
|
|
314
|
+
}
|
|
315
|
+
);
|
|
309
316
|
|
|
310
317
|
return <DataEditor data={data} onChange={setData} />;
|
|
311
318
|
}
|
|
@@ -314,11 +321,11 @@ function RobustStorage() {
|
|
|
314
321
|
### Cross-Tab Synchronization
|
|
315
322
|
|
|
316
323
|
```tsx
|
|
317
|
-
import { useLocalStorage } from
|
|
324
|
+
import { useLocalStorage } from "@usefy/use-local-storage";
|
|
318
325
|
|
|
319
326
|
function CartCounter() {
|
|
320
327
|
// Changes in one tab automatically sync to other tabs
|
|
321
|
-
const [cartItems, setCartItems] = useLocalStorage<string[]>(
|
|
328
|
+
const [cartItems, setCartItems] = useLocalStorage<string[]>("cart", []);
|
|
322
329
|
|
|
323
330
|
const addItem = (item: string) => {
|
|
324
331
|
setCartItems((prev) => [...prev, item]);
|
|
@@ -336,11 +343,11 @@ function CartCounter() {
|
|
|
336
343
|
### Disable Tab Sync
|
|
337
344
|
|
|
338
345
|
```tsx
|
|
339
|
-
import { useLocalStorage } from
|
|
346
|
+
import { useLocalStorage } from "@usefy/use-local-storage";
|
|
340
347
|
|
|
341
348
|
function LocalOnlyData() {
|
|
342
349
|
// Don't sync changes from other tabs
|
|
343
|
-
const [draft, setDraft] = useLocalStorage(
|
|
350
|
+
const [draft, setDraft] = useLocalStorage("draft", "", {
|
|
344
351
|
syncTabs: false,
|
|
345
352
|
});
|
|
346
353
|
|
|
@@ -357,7 +364,7 @@ function LocalOnlyData() {
|
|
|
357
364
|
### Shopping Cart
|
|
358
365
|
|
|
359
366
|
```tsx
|
|
360
|
-
import { useLocalStorage } from
|
|
367
|
+
import { useLocalStorage } from "@usefy/use-local-storage";
|
|
361
368
|
|
|
362
369
|
interface CartItem {
|
|
363
370
|
id: string;
|
|
@@ -367,7 +374,7 @@ interface CartItem {
|
|
|
367
374
|
}
|
|
368
375
|
|
|
369
376
|
function ShoppingCart() {
|
|
370
|
-
const [cart, setCart, clearCart] = useLocalStorage<CartItem[]>(
|
|
377
|
+
const [cart, setCart, clearCart] = useLocalStorage<CartItem[]>("cart", []);
|
|
371
378
|
|
|
372
379
|
const addToCart = (product: Product) => {
|
|
373
380
|
setCart((prev) => {
|
|
@@ -414,19 +421,19 @@ import {
|
|
|
414
421
|
type UseLocalStorageOptions,
|
|
415
422
|
type UseLocalStorageReturn,
|
|
416
423
|
type InitialValue,
|
|
417
|
-
} from
|
|
424
|
+
} from "@usefy/use-local-storage";
|
|
418
425
|
|
|
419
426
|
// Generic type inference
|
|
420
|
-
const [name, setName] = useLocalStorage(
|
|
421
|
-
const [count, setCount] = useLocalStorage(
|
|
422
|
-
const [items, setItems] = useLocalStorage(
|
|
427
|
+
const [name, setName] = useLocalStorage("name", "John"); // string
|
|
428
|
+
const [count, setCount] = useLocalStorage("count", 0); // number
|
|
429
|
+
const [items, setItems] = useLocalStorage("items", [1, 2]); // number[]
|
|
423
430
|
|
|
424
431
|
// Explicit generic type
|
|
425
432
|
interface User {
|
|
426
433
|
id: string;
|
|
427
434
|
name: string;
|
|
428
435
|
}
|
|
429
|
-
const [user, setUser] = useLocalStorage<User | null>(
|
|
436
|
+
const [user, setUser] = useLocalStorage<User | null>("user", null);
|
|
430
437
|
```
|
|
431
438
|
|
|
432
439
|
---
|
|
@@ -437,12 +444,12 @@ This package maintains comprehensive test coverage to ensure reliability and sta
|
|
|
437
444
|
|
|
438
445
|
### Test Coverage
|
|
439
446
|
|
|
440
|
-
| Category
|
|
441
|
-
|
|
447
|
+
| Category | Coverage |
|
|
448
|
+
| ---------- | -------------- |
|
|
442
449
|
| Statements | 95.16% (59/62) |
|
|
443
|
-
| Branches
|
|
444
|
-
| Functions
|
|
445
|
-
| Lines
|
|
450
|
+
| Branches | 85.71% (24/28) |
|
|
451
|
+
| Functions | 100% (9/9) |
|
|
452
|
+
| Lines | 95.08% (58/61) |
|
|
446
453
|
|
|
447
454
|
### Test Categories
|
|
448
455
|
|
|
@@ -488,14 +495,14 @@ pnpm test --coverage
|
|
|
488
495
|
|
|
489
496
|
Explore other hooks in the **@usefy** collection:
|
|
490
497
|
|
|
491
|
-
| Package
|
|
492
|
-
|
|
498
|
+
| Package | Description |
|
|
499
|
+
| -------------------------------------------------------------------------------------- | --------------------------- |
|
|
493
500
|
| [@usefy/use-session-storage](https://www.npmjs.com/package/@usefy/use-session-storage) | Session storage persistence |
|
|
494
|
-
| [@usefy/use-toggle](https://www.npmjs.com/package/@usefy/use-toggle)
|
|
495
|
-
| [@usefy/use-counter](https://www.npmjs.com/package/@usefy/use-counter)
|
|
496
|
-
| [@usefy/use-debounce](https://www.npmjs.com/package/@usefy/use-debounce)
|
|
497
|
-
| [@usefy/use-throttle](https://www.npmjs.com/package/@usefy/use-throttle)
|
|
498
|
-
| [@usefy/use-click-any-where](https://www.npmjs.com/package/@usefy/use-click-any-where) | Global click detection
|
|
501
|
+
| [@usefy/use-toggle](https://www.npmjs.com/package/@usefy/use-toggle) | Boolean state management |
|
|
502
|
+
| [@usefy/use-counter](https://www.npmjs.com/package/@usefy/use-counter) | Counter state management |
|
|
503
|
+
| [@usefy/use-debounce](https://www.npmjs.com/package/@usefy/use-debounce) | Value debouncing |
|
|
504
|
+
| [@usefy/use-throttle](https://www.npmjs.com/package/@usefy/use-throttle) | Value throttling |
|
|
505
|
+
| [@usefy/use-click-any-where](https://www.npmjs.com/package/@usefy/use-click-any-where) | Global click detection |
|
|
499
506
|
|
|
500
507
|
---
|
|
501
508
|
|
package/package.json
CHANGED