@usefy/use-local-storage 0.0.2
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/dist/index.d.mts +109 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.js +136 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +109 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +59 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type for initial value that can be a value or a function returning a value (lazy initialization)
|
|
3
|
+
*/
|
|
4
|
+
type InitialValue<T> = T | (() => T);
|
|
5
|
+
/**
|
|
6
|
+
* Options for useLocalStorage hook
|
|
7
|
+
*/
|
|
8
|
+
interface UseLocalStorageOptions<T> {
|
|
9
|
+
/**
|
|
10
|
+
* Custom serializer function for converting value to string
|
|
11
|
+
* @default JSON.stringify
|
|
12
|
+
*/
|
|
13
|
+
serializer?: (value: T) => string;
|
|
14
|
+
/**
|
|
15
|
+
* Custom deserializer function for parsing stored string to value
|
|
16
|
+
* @default JSON.parse
|
|
17
|
+
*/
|
|
18
|
+
deserializer?: (value: string) => T;
|
|
19
|
+
/**
|
|
20
|
+
* Whether to sync value across browser tabs via storage event
|
|
21
|
+
* @default true
|
|
22
|
+
*/
|
|
23
|
+
syncTabs?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Callback function called when an error occurs
|
|
26
|
+
*/
|
|
27
|
+
onError?: (error: Error) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Return type for useLocalStorage hook - tuple similar to useState
|
|
31
|
+
*/
|
|
32
|
+
type UseLocalStorageReturn<T> = readonly [
|
|
33
|
+
/** Current stored value */
|
|
34
|
+
T,
|
|
35
|
+
/** Function to update the value (same signature as useState setter) */
|
|
36
|
+
React.Dispatch<React.SetStateAction<T>>,
|
|
37
|
+
/** Function to remove the value from localStorage */
|
|
38
|
+
() => void
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* A hook for persisting state in localStorage with automatic synchronization.
|
|
42
|
+
* Works like useState but persists the value in localStorage.
|
|
43
|
+
*
|
|
44
|
+
* @template T - The type of the stored value
|
|
45
|
+
* @param key - The localStorage key to store the value under
|
|
46
|
+
* @param initialValue - Initial value or function returning initial value (lazy initialization)
|
|
47
|
+
* @param options - Configuration options for serialization, sync, and error handling
|
|
48
|
+
* @returns A tuple of [storedValue, setValue, removeValue]
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* // Basic usage with string
|
|
53
|
+
* function ThemeToggle() {
|
|
54
|
+
* const [theme, setTheme, removeTheme] = useLocalStorage('theme', 'light');
|
|
55
|
+
*
|
|
56
|
+
* return (
|
|
57
|
+
* <div>
|
|
58
|
+
* <p>Current theme: {theme}</p>
|
|
59
|
+
* <button onClick={() => setTheme('dark')}>Dark</button>
|
|
60
|
+
* <button onClick={() => setTheme('light')}>Light</button>
|
|
61
|
+
* <button onClick={removeTheme}>Reset</button>
|
|
62
|
+
* </div>
|
|
63
|
+
* );
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```tsx
|
|
69
|
+
* // With object type
|
|
70
|
+
* interface UserSettings {
|
|
71
|
+
* notifications: boolean;
|
|
72
|
+
* language: string;
|
|
73
|
+
* }
|
|
74
|
+
*
|
|
75
|
+
* const [settings, setSettings] = useLocalStorage<UserSettings>('settings', {
|
|
76
|
+
* notifications: true,
|
|
77
|
+
* language: 'en',
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* // Functional update
|
|
81
|
+
* setSettings(prev => ({ ...prev, notifications: false }));
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```tsx
|
|
86
|
+
* // With lazy initialization
|
|
87
|
+
* const [config, setConfig] = useLocalStorage('config', () => computeExpensiveDefault());
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```tsx
|
|
92
|
+
* // With custom serializer/deserializer
|
|
93
|
+
* const [date, setDate] = useLocalStorage<Date>('lastVisit', new Date(), {
|
|
94
|
+
* serializer: (d) => d.toISOString(),
|
|
95
|
+
* deserializer: (s) => new Date(s),
|
|
96
|
+
* });
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```tsx
|
|
101
|
+
* // With error handling
|
|
102
|
+
* const [value, setValue] = useLocalStorage('key', 'default', {
|
|
103
|
+
* onError: (error) => console.error('Storage error:', error),
|
|
104
|
+
* });
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare function useLocalStorage<T>(key: string, initialValue: InitialValue<T>, options?: UseLocalStorageOptions<T>): UseLocalStorageReturn<T>;
|
|
108
|
+
|
|
109
|
+
export { type InitialValue, type UseLocalStorageOptions, type UseLocalStorageReturn, useLocalStorage };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type for initial value that can be a value or a function returning a value (lazy initialization)
|
|
3
|
+
*/
|
|
4
|
+
type InitialValue<T> = T | (() => T);
|
|
5
|
+
/**
|
|
6
|
+
* Options for useLocalStorage hook
|
|
7
|
+
*/
|
|
8
|
+
interface UseLocalStorageOptions<T> {
|
|
9
|
+
/**
|
|
10
|
+
* Custom serializer function for converting value to string
|
|
11
|
+
* @default JSON.stringify
|
|
12
|
+
*/
|
|
13
|
+
serializer?: (value: T) => string;
|
|
14
|
+
/**
|
|
15
|
+
* Custom deserializer function for parsing stored string to value
|
|
16
|
+
* @default JSON.parse
|
|
17
|
+
*/
|
|
18
|
+
deserializer?: (value: string) => T;
|
|
19
|
+
/**
|
|
20
|
+
* Whether to sync value across browser tabs via storage event
|
|
21
|
+
* @default true
|
|
22
|
+
*/
|
|
23
|
+
syncTabs?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Callback function called when an error occurs
|
|
26
|
+
*/
|
|
27
|
+
onError?: (error: Error) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Return type for useLocalStorage hook - tuple similar to useState
|
|
31
|
+
*/
|
|
32
|
+
type UseLocalStorageReturn<T> = readonly [
|
|
33
|
+
/** Current stored value */
|
|
34
|
+
T,
|
|
35
|
+
/** Function to update the value (same signature as useState setter) */
|
|
36
|
+
React.Dispatch<React.SetStateAction<T>>,
|
|
37
|
+
/** Function to remove the value from localStorage */
|
|
38
|
+
() => void
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* A hook for persisting state in localStorage with automatic synchronization.
|
|
42
|
+
* Works like useState but persists the value in localStorage.
|
|
43
|
+
*
|
|
44
|
+
* @template T - The type of the stored value
|
|
45
|
+
* @param key - The localStorage key to store the value under
|
|
46
|
+
* @param initialValue - Initial value or function returning initial value (lazy initialization)
|
|
47
|
+
* @param options - Configuration options for serialization, sync, and error handling
|
|
48
|
+
* @returns A tuple of [storedValue, setValue, removeValue]
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* // Basic usage with string
|
|
53
|
+
* function ThemeToggle() {
|
|
54
|
+
* const [theme, setTheme, removeTheme] = useLocalStorage('theme', 'light');
|
|
55
|
+
*
|
|
56
|
+
* return (
|
|
57
|
+
* <div>
|
|
58
|
+
* <p>Current theme: {theme}</p>
|
|
59
|
+
* <button onClick={() => setTheme('dark')}>Dark</button>
|
|
60
|
+
* <button onClick={() => setTheme('light')}>Light</button>
|
|
61
|
+
* <button onClick={removeTheme}>Reset</button>
|
|
62
|
+
* </div>
|
|
63
|
+
* );
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```tsx
|
|
69
|
+
* // With object type
|
|
70
|
+
* interface UserSettings {
|
|
71
|
+
* notifications: boolean;
|
|
72
|
+
* language: string;
|
|
73
|
+
* }
|
|
74
|
+
*
|
|
75
|
+
* const [settings, setSettings] = useLocalStorage<UserSettings>('settings', {
|
|
76
|
+
* notifications: true,
|
|
77
|
+
* language: 'en',
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* // Functional update
|
|
81
|
+
* setSettings(prev => ({ ...prev, notifications: false }));
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```tsx
|
|
86
|
+
* // With lazy initialization
|
|
87
|
+
* const [config, setConfig] = useLocalStorage('config', () => computeExpensiveDefault());
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```tsx
|
|
92
|
+
* // With custom serializer/deserializer
|
|
93
|
+
* const [date, setDate] = useLocalStorage<Date>('lastVisit', new Date(), {
|
|
94
|
+
* serializer: (d) => d.toISOString(),
|
|
95
|
+
* deserializer: (s) => new Date(s),
|
|
96
|
+
* });
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```tsx
|
|
101
|
+
* // With error handling
|
|
102
|
+
* const [value, setValue] = useLocalStorage('key', 'default', {
|
|
103
|
+
* onError: (error) => console.error('Storage error:', error),
|
|
104
|
+
* });
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare function useLocalStorage<T>(key: string, initialValue: InitialValue<T>, options?: UseLocalStorageOptions<T>): UseLocalStorageReturn<T>;
|
|
108
|
+
|
|
109
|
+
export { type InitialValue, type UseLocalStorageOptions, type UseLocalStorageReturn, useLocalStorage };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
useLocalStorage: () => useLocalStorage
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/useLocalStorage.ts
|
|
28
|
+
var import_react = require("react");
|
|
29
|
+
function resolveInitialValue(initialValue) {
|
|
30
|
+
return typeof initialValue === "function" ? initialValue() : initialValue;
|
|
31
|
+
}
|
|
32
|
+
function useLocalStorage(key, initialValue, options = {}) {
|
|
33
|
+
const {
|
|
34
|
+
serializer = JSON.stringify,
|
|
35
|
+
deserializer = JSON.parse,
|
|
36
|
+
syncTabs = true,
|
|
37
|
+
onError
|
|
38
|
+
} = options;
|
|
39
|
+
const serializerRef = (0, import_react.useRef)(serializer);
|
|
40
|
+
const deserializerRef = (0, import_react.useRef)(deserializer);
|
|
41
|
+
const onErrorRef = (0, import_react.useRef)(onError);
|
|
42
|
+
serializerRef.current = serializer;
|
|
43
|
+
deserializerRef.current = deserializer;
|
|
44
|
+
onErrorRef.current = onError;
|
|
45
|
+
const initialValueRef = (0, import_react.useRef)(initialValue);
|
|
46
|
+
initialValueRef.current = initialValue;
|
|
47
|
+
const isClient = typeof window !== "undefined";
|
|
48
|
+
const [storedValue, setStoredValue] = (0, import_react.useState)(() => {
|
|
49
|
+
if (!isClient) {
|
|
50
|
+
return resolveInitialValue(initialValue);
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const item = window.localStorage.getItem(key);
|
|
54
|
+
if (item !== null) {
|
|
55
|
+
return deserializerRef.current(item);
|
|
56
|
+
}
|
|
57
|
+
return resolveInitialValue(initialValue);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
onErrorRef.current?.(error);
|
|
60
|
+
return resolveInitialValue(initialValue);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const storedValueRef = (0, import_react.useRef)(storedValue);
|
|
64
|
+
storedValueRef.current = storedValue;
|
|
65
|
+
const setValue = (0, import_react.useCallback)(
|
|
66
|
+
(value) => {
|
|
67
|
+
try {
|
|
68
|
+
const currentValue = storedValueRef.current;
|
|
69
|
+
const valueToStore = value instanceof Function ? value(currentValue) : value;
|
|
70
|
+
setStoredValue(valueToStore);
|
|
71
|
+
if (typeof window !== "undefined") {
|
|
72
|
+
window.localStorage.setItem(
|
|
73
|
+
key,
|
|
74
|
+
serializerRef.current(valueToStore)
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
onErrorRef.current?.(error);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
[key]
|
|
82
|
+
);
|
|
83
|
+
const removeValue = (0, import_react.useCallback)(() => {
|
|
84
|
+
try {
|
|
85
|
+
const initial = resolveInitialValue(initialValueRef.current);
|
|
86
|
+
setStoredValue(initial);
|
|
87
|
+
if (typeof window !== "undefined") {
|
|
88
|
+
window.localStorage.removeItem(key);
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
onErrorRef.current?.(error);
|
|
92
|
+
}
|
|
93
|
+
}, [key]);
|
|
94
|
+
(0, import_react.useEffect)(() => {
|
|
95
|
+
if (!isClient || !syncTabs) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const handleStorageChange = (event) => {
|
|
99
|
+
if (event.key !== key) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (event.newValue !== null) {
|
|
103
|
+
try {
|
|
104
|
+
setStoredValue(deserializerRef.current(event.newValue));
|
|
105
|
+
} catch {
|
|
106
|
+
setStoredValue(resolveInitialValue(initialValueRef.current));
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
setStoredValue(resolveInitialValue(initialValueRef.current));
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
window.addEventListener("storage", handleStorageChange);
|
|
113
|
+
return () => window.removeEventListener("storage", handleStorageChange);
|
|
114
|
+
}, [key, syncTabs, isClient]);
|
|
115
|
+
(0, import_react.useEffect)(() => {
|
|
116
|
+
if (!isClient) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const item = window.localStorage.getItem(key);
|
|
121
|
+
if (item !== null) {
|
|
122
|
+
setStoredValue(deserializerRef.current(item));
|
|
123
|
+
} else {
|
|
124
|
+
setStoredValue(resolveInitialValue(initialValueRef.current));
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
setStoredValue(resolveInitialValue(initialValueRef.current));
|
|
128
|
+
}
|
|
129
|
+
}, [key]);
|
|
130
|
+
return [storedValue, setValue, removeValue];
|
|
131
|
+
}
|
|
132
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
133
|
+
0 && (module.exports = {
|
|
134
|
+
useLocalStorage
|
|
135
|
+
});
|
|
136
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/useLocalStorage.ts"],"sourcesContent":["export {\r\n useLocalStorage,\r\n type UseLocalStorageOptions,\r\n type UseLocalStorageReturn,\r\n type InitialValue,\r\n} from \"./useLocalStorage\";\r\n","import { useCallback, useEffect, useRef, useState } from \"react\";\r\n\r\n/**\r\n * Type for initial value that can be a value or a function returning a value (lazy initialization)\r\n */\r\nexport type InitialValue<T> = T | (() => T);\r\n\r\n/**\r\n * Options for useLocalStorage hook\r\n */\r\nexport interface UseLocalStorageOptions<T> {\r\n /**\r\n * Custom serializer function for converting value to string\r\n * @default JSON.stringify\r\n */\r\n serializer?: (value: T) => string;\r\n /**\r\n * Custom deserializer function for parsing stored string to value\r\n * @default JSON.parse\r\n */\r\n deserializer?: (value: string) => T;\r\n /**\r\n * Whether to sync value across browser tabs via storage event\r\n * @default true\r\n */\r\n syncTabs?: boolean;\r\n /**\r\n * Callback function called when an error occurs\r\n */\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * Return type for useLocalStorage hook - tuple similar to useState\r\n */\r\nexport type UseLocalStorageReturn<T> = readonly [\r\n /** Current stored value */\r\n T,\r\n /** Function to update the value (same signature as useState setter) */\r\n React.Dispatch<React.SetStateAction<T>>,\r\n /** Function to remove the value from localStorage */\r\n () => void\r\n];\r\n\r\n/**\r\n * Helper function to resolve initial value (supports lazy initialization)\r\n */\r\nfunction resolveInitialValue<T>(initialValue: InitialValue<T>): T {\r\n return typeof initialValue === \"function\"\r\n ? (initialValue as () => T)()\r\n : initialValue;\r\n}\r\n\r\n/**\r\n * A hook for persisting state in localStorage with automatic synchronization.\r\n * Works like useState but persists the value in localStorage.\r\n *\r\n * @template T - The type of the stored value\r\n * @param key - The localStorage key to store the value under\r\n * @param initialValue - Initial value or function returning initial value (lazy initialization)\r\n * @param options - Configuration options for serialization, sync, and error handling\r\n * @returns A tuple of [storedValue, setValue, removeValue]\r\n *\r\n * @example\r\n * ```tsx\r\n * // Basic usage with string\r\n * function ThemeToggle() {\r\n * const [theme, setTheme, removeTheme] = useLocalStorage('theme', 'light');\r\n *\r\n * return (\r\n * <div>\r\n * <p>Current theme: {theme}</p>\r\n * <button onClick={() => setTheme('dark')}>Dark</button>\r\n * <button onClick={() => setTheme('light')}>Light</button>\r\n * <button onClick={removeTheme}>Reset</button>\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With object type\r\n * interface UserSettings {\r\n * notifications: boolean;\r\n * language: string;\r\n * }\r\n *\r\n * const [settings, setSettings] = useLocalStorage<UserSettings>('settings', {\r\n * notifications: true,\r\n * language: 'en',\r\n * });\r\n *\r\n * // Functional update\r\n * setSettings(prev => ({ ...prev, notifications: false }));\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With lazy initialization\r\n * const [config, setConfig] = useLocalStorage('config', () => computeExpensiveDefault());\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With custom serializer/deserializer\r\n * const [date, setDate] = useLocalStorage<Date>('lastVisit', new Date(), {\r\n * serializer: (d) => d.toISOString(),\r\n * deserializer: (s) => new Date(s),\r\n * });\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With error handling\r\n * const [value, setValue] = useLocalStorage('key', 'default', {\r\n * onError: (error) => console.error('Storage error:', error),\r\n * });\r\n * ```\r\n */\r\nexport function useLocalStorage<T>(\r\n key: string,\r\n initialValue: InitialValue<T>,\r\n options: UseLocalStorageOptions<T> = {}\r\n): UseLocalStorageReturn<T> {\r\n const {\r\n serializer = JSON.stringify,\r\n deserializer = JSON.parse,\r\n syncTabs = true,\r\n onError,\r\n } = options;\r\n\r\n // Store options in refs for stable references and access to latest values\r\n const serializerRef = useRef(serializer);\r\n const deserializerRef = useRef(deserializer);\r\n const onErrorRef = useRef(onError);\r\n serializerRef.current = serializer;\r\n deserializerRef.current = deserializer;\r\n onErrorRef.current = onError;\r\n\r\n // Store initialValue in ref for use in removeValue and storage event handler\r\n const initialValueRef = useRef(initialValue);\r\n initialValueRef.current = initialValue;\r\n\r\n // SSR check - check once at module level for consistency\r\n const isClient = typeof window !== \"undefined\";\r\n\r\n // Lazy initialization with localStorage read\r\n const [storedValue, setStoredValue] = useState<T>(() => {\r\n if (!isClient) {\r\n return resolveInitialValue(initialValue);\r\n }\r\n\r\n try {\r\n const item = window.localStorage.getItem(key);\r\n if (item !== null) {\r\n return deserializerRef.current(item);\r\n }\r\n return resolveInitialValue(initialValue);\r\n } catch (error) {\r\n onErrorRef.current?.(error as Error);\r\n return resolveInitialValue(initialValue);\r\n }\r\n });\r\n\r\n // Store current value in ref for stable setValue reference\r\n const storedValueRef = useRef<T>(storedValue);\r\n storedValueRef.current = storedValue;\r\n\r\n // setValue - stable reference (only depends on key)\r\n const setValue = useCallback<React.Dispatch<React.SetStateAction<T>>>(\r\n (value) => {\r\n try {\r\n const currentValue = storedValueRef.current;\r\n const valueToStore =\r\n value instanceof Function ? value(currentValue) : value;\r\n\r\n setStoredValue(valueToStore);\r\n\r\n if (typeof window !== \"undefined\") {\r\n window.localStorage.setItem(\r\n key,\r\n serializerRef.current(valueToStore)\r\n );\r\n }\r\n } catch (error) {\r\n onErrorRef.current?.(error as Error);\r\n }\r\n },\r\n [key]\r\n );\r\n\r\n // removeValue - stable reference\r\n const removeValue = useCallback(() => {\r\n try {\r\n const initial = resolveInitialValue(initialValueRef.current);\r\n setStoredValue(initial);\r\n\r\n if (typeof window !== \"undefined\") {\r\n window.localStorage.removeItem(key);\r\n }\r\n } catch (error) {\r\n onErrorRef.current?.(error as Error);\r\n }\r\n }, [key]);\r\n\r\n // Cross-tab synchronization via storage event\r\n useEffect(() => {\r\n if (!isClient || !syncTabs) {\r\n return;\r\n }\r\n\r\n const handleStorageChange = (event: StorageEvent) => {\r\n if (event.key !== key) {\r\n return;\r\n }\r\n\r\n if (event.newValue !== null) {\r\n try {\r\n setStoredValue(deserializerRef.current(event.newValue));\r\n } catch {\r\n // If parsing fails, reset to initial value\r\n setStoredValue(resolveInitialValue(initialValueRef.current));\r\n }\r\n } else {\r\n // Key was removed in another tab\r\n setStoredValue(resolveInitialValue(initialValueRef.current));\r\n }\r\n };\r\n\r\n window.addEventListener(\"storage\", handleStorageChange);\r\n return () => window.removeEventListener(\"storage\", handleStorageChange);\r\n }, [key, syncTabs, isClient]);\r\n\r\n // Re-read value when key changes\r\n useEffect(() => {\r\n if (!isClient) {\r\n return;\r\n }\r\n\r\n try {\r\n const item = window.localStorage.getItem(key);\r\n if (item !== null) {\r\n setStoredValue(deserializerRef.current(item));\r\n } else {\r\n setStoredValue(resolveInitialValue(initialValueRef.current));\r\n }\r\n } catch {\r\n setStoredValue(resolveInitialValue(initialValueRef.current));\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [key]);\r\n\r\n return [storedValue, setValue, removeValue] as const;\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// src/useLocalStorage.ts
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
function resolveInitialValue(initialValue) {
|
|
4
|
+
return typeof initialValue === "function" ? initialValue() : initialValue;
|
|
5
|
+
}
|
|
6
|
+
function useLocalStorage(key, initialValue, options = {}) {
|
|
7
|
+
const {
|
|
8
|
+
serializer = JSON.stringify,
|
|
9
|
+
deserializer = JSON.parse,
|
|
10
|
+
syncTabs = true,
|
|
11
|
+
onError
|
|
12
|
+
} = options;
|
|
13
|
+
const serializerRef = useRef(serializer);
|
|
14
|
+
const deserializerRef = useRef(deserializer);
|
|
15
|
+
const onErrorRef = useRef(onError);
|
|
16
|
+
serializerRef.current = serializer;
|
|
17
|
+
deserializerRef.current = deserializer;
|
|
18
|
+
onErrorRef.current = onError;
|
|
19
|
+
const initialValueRef = useRef(initialValue);
|
|
20
|
+
initialValueRef.current = initialValue;
|
|
21
|
+
const isClient = typeof window !== "undefined";
|
|
22
|
+
const [storedValue, setStoredValue] = useState(() => {
|
|
23
|
+
if (!isClient) {
|
|
24
|
+
return resolveInitialValue(initialValue);
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const item = window.localStorage.getItem(key);
|
|
28
|
+
if (item !== null) {
|
|
29
|
+
return deserializerRef.current(item);
|
|
30
|
+
}
|
|
31
|
+
return resolveInitialValue(initialValue);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
onErrorRef.current?.(error);
|
|
34
|
+
return resolveInitialValue(initialValue);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const storedValueRef = useRef(storedValue);
|
|
38
|
+
storedValueRef.current = storedValue;
|
|
39
|
+
const setValue = useCallback(
|
|
40
|
+
(value) => {
|
|
41
|
+
try {
|
|
42
|
+
const currentValue = storedValueRef.current;
|
|
43
|
+
const valueToStore = value instanceof Function ? value(currentValue) : value;
|
|
44
|
+
setStoredValue(valueToStore);
|
|
45
|
+
if (typeof window !== "undefined") {
|
|
46
|
+
window.localStorage.setItem(
|
|
47
|
+
key,
|
|
48
|
+
serializerRef.current(valueToStore)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
onErrorRef.current?.(error);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
[key]
|
|
56
|
+
);
|
|
57
|
+
const removeValue = useCallback(() => {
|
|
58
|
+
try {
|
|
59
|
+
const initial = resolveInitialValue(initialValueRef.current);
|
|
60
|
+
setStoredValue(initial);
|
|
61
|
+
if (typeof window !== "undefined") {
|
|
62
|
+
window.localStorage.removeItem(key);
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
onErrorRef.current?.(error);
|
|
66
|
+
}
|
|
67
|
+
}, [key]);
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (!isClient || !syncTabs) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const handleStorageChange = (event) => {
|
|
73
|
+
if (event.key !== key) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (event.newValue !== null) {
|
|
77
|
+
try {
|
|
78
|
+
setStoredValue(deserializerRef.current(event.newValue));
|
|
79
|
+
} catch {
|
|
80
|
+
setStoredValue(resolveInitialValue(initialValueRef.current));
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
setStoredValue(resolveInitialValue(initialValueRef.current));
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
window.addEventListener("storage", handleStorageChange);
|
|
87
|
+
return () => window.removeEventListener("storage", handleStorageChange);
|
|
88
|
+
}, [key, syncTabs, isClient]);
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
if (!isClient) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const item = window.localStorage.getItem(key);
|
|
95
|
+
if (item !== null) {
|
|
96
|
+
setStoredValue(deserializerRef.current(item));
|
|
97
|
+
} else {
|
|
98
|
+
setStoredValue(resolveInitialValue(initialValueRef.current));
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
setStoredValue(resolveInitialValue(initialValueRef.current));
|
|
102
|
+
}
|
|
103
|
+
}, [key]);
|
|
104
|
+
return [storedValue, setValue, removeValue];
|
|
105
|
+
}
|
|
106
|
+
export {
|
|
107
|
+
useLocalStorage
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/useLocalStorage.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\r\n\r\n/**\r\n * Type for initial value that can be a value or a function returning a value (lazy initialization)\r\n */\r\nexport type InitialValue<T> = T | (() => T);\r\n\r\n/**\r\n * Options for useLocalStorage hook\r\n */\r\nexport interface UseLocalStorageOptions<T> {\r\n /**\r\n * Custom serializer function for converting value to string\r\n * @default JSON.stringify\r\n */\r\n serializer?: (value: T) => string;\r\n /**\r\n * Custom deserializer function for parsing stored string to value\r\n * @default JSON.parse\r\n */\r\n deserializer?: (value: string) => T;\r\n /**\r\n * Whether to sync value across browser tabs via storage event\r\n * @default true\r\n */\r\n syncTabs?: boolean;\r\n /**\r\n * Callback function called when an error occurs\r\n */\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * Return type for useLocalStorage hook - tuple similar to useState\r\n */\r\nexport type UseLocalStorageReturn<T> = readonly [\r\n /** Current stored value */\r\n T,\r\n /** Function to update the value (same signature as useState setter) */\r\n React.Dispatch<React.SetStateAction<T>>,\r\n /** Function to remove the value from localStorage */\r\n () => void\r\n];\r\n\r\n/**\r\n * Helper function to resolve initial value (supports lazy initialization)\r\n */\r\nfunction resolveInitialValue<T>(initialValue: InitialValue<T>): T {\r\n return typeof initialValue === \"function\"\r\n ? (initialValue as () => T)()\r\n : initialValue;\r\n}\r\n\r\n/**\r\n * A hook for persisting state in localStorage with automatic synchronization.\r\n * Works like useState but persists the value in localStorage.\r\n *\r\n * @template T - The type of the stored value\r\n * @param key - The localStorage key to store the value under\r\n * @param initialValue - Initial value or function returning initial value (lazy initialization)\r\n * @param options - Configuration options for serialization, sync, and error handling\r\n * @returns A tuple of [storedValue, setValue, removeValue]\r\n *\r\n * @example\r\n * ```tsx\r\n * // Basic usage with string\r\n * function ThemeToggle() {\r\n * const [theme, setTheme, removeTheme] = useLocalStorage('theme', 'light');\r\n *\r\n * return (\r\n * <div>\r\n * <p>Current theme: {theme}</p>\r\n * <button onClick={() => setTheme('dark')}>Dark</button>\r\n * <button onClick={() => setTheme('light')}>Light</button>\r\n * <button onClick={removeTheme}>Reset</button>\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With object type\r\n * interface UserSettings {\r\n * notifications: boolean;\r\n * language: string;\r\n * }\r\n *\r\n * const [settings, setSettings] = useLocalStorage<UserSettings>('settings', {\r\n * notifications: true,\r\n * language: 'en',\r\n * });\r\n *\r\n * // Functional update\r\n * setSettings(prev => ({ ...prev, notifications: false }));\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With lazy initialization\r\n * const [config, setConfig] = useLocalStorage('config', () => computeExpensiveDefault());\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With custom serializer/deserializer\r\n * const [date, setDate] = useLocalStorage<Date>('lastVisit', new Date(), {\r\n * serializer: (d) => d.toISOString(),\r\n * deserializer: (s) => new Date(s),\r\n * });\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With error handling\r\n * const [value, setValue] = useLocalStorage('key', 'default', {\r\n * onError: (error) => console.error('Storage error:', error),\r\n * });\r\n * ```\r\n */\r\nexport function useLocalStorage<T>(\r\n key: string,\r\n initialValue: InitialValue<T>,\r\n options: UseLocalStorageOptions<T> = {}\r\n): UseLocalStorageReturn<T> {\r\n const {\r\n serializer = JSON.stringify,\r\n deserializer = JSON.parse,\r\n syncTabs = true,\r\n onError,\r\n } = options;\r\n\r\n // Store options in refs for stable references and access to latest values\r\n const serializerRef = useRef(serializer);\r\n const deserializerRef = useRef(deserializer);\r\n const onErrorRef = useRef(onError);\r\n serializerRef.current = serializer;\r\n deserializerRef.current = deserializer;\r\n onErrorRef.current = onError;\r\n\r\n // Store initialValue in ref for use in removeValue and storage event handler\r\n const initialValueRef = useRef(initialValue);\r\n initialValueRef.current = initialValue;\r\n\r\n // SSR check - check once at module level for consistency\r\n const isClient = typeof window !== \"undefined\";\r\n\r\n // Lazy initialization with localStorage read\r\n const [storedValue, setStoredValue] = useState<T>(() => {\r\n if (!isClient) {\r\n return resolveInitialValue(initialValue);\r\n }\r\n\r\n try {\r\n const item = window.localStorage.getItem(key);\r\n if (item !== null) {\r\n return deserializerRef.current(item);\r\n }\r\n return resolveInitialValue(initialValue);\r\n } catch (error) {\r\n onErrorRef.current?.(error as Error);\r\n return resolveInitialValue(initialValue);\r\n }\r\n });\r\n\r\n // Store current value in ref for stable setValue reference\r\n const storedValueRef = useRef<T>(storedValue);\r\n storedValueRef.current = storedValue;\r\n\r\n // setValue - stable reference (only depends on key)\r\n const setValue = useCallback<React.Dispatch<React.SetStateAction<T>>>(\r\n (value) => {\r\n try {\r\n const currentValue = storedValueRef.current;\r\n const valueToStore =\r\n value instanceof Function ? value(currentValue) : value;\r\n\r\n setStoredValue(valueToStore);\r\n\r\n if (typeof window !== \"undefined\") {\r\n window.localStorage.setItem(\r\n key,\r\n serializerRef.current(valueToStore)\r\n );\r\n }\r\n } catch (error) {\r\n onErrorRef.current?.(error as Error);\r\n }\r\n },\r\n [key]\r\n );\r\n\r\n // removeValue - stable reference\r\n const removeValue = useCallback(() => {\r\n try {\r\n const initial = resolveInitialValue(initialValueRef.current);\r\n setStoredValue(initial);\r\n\r\n if (typeof window !== \"undefined\") {\r\n window.localStorage.removeItem(key);\r\n }\r\n } catch (error) {\r\n onErrorRef.current?.(error as Error);\r\n }\r\n }, [key]);\r\n\r\n // Cross-tab synchronization via storage event\r\n useEffect(() => {\r\n if (!isClient || !syncTabs) {\r\n return;\r\n }\r\n\r\n const handleStorageChange = (event: StorageEvent) => {\r\n if (event.key !== key) {\r\n return;\r\n }\r\n\r\n if (event.newValue !== null) {\r\n try {\r\n setStoredValue(deserializerRef.current(event.newValue));\r\n } catch {\r\n // If parsing fails, reset to initial value\r\n setStoredValue(resolveInitialValue(initialValueRef.current));\r\n }\r\n } else {\r\n // Key was removed in another tab\r\n setStoredValue(resolveInitialValue(initialValueRef.current));\r\n }\r\n };\r\n\r\n window.addEventListener(\"storage\", handleStorageChange);\r\n return () => window.removeEventListener(\"storage\", handleStorageChange);\r\n }, [key, syncTabs, isClient]);\r\n\r\n // Re-read value when key changes\r\n useEffect(() => {\r\n if (!isClient) {\r\n return;\r\n }\r\n\r\n try {\r\n const item = window.localStorage.getItem(key);\r\n if (item !== null) {\r\n setStoredValue(deserializerRef.current(item));\r\n } else {\r\n setStoredValue(resolveInitialValue(initialValueRef.current));\r\n }\r\n } catch {\r\n setStoredValue(resolveInitialValue(initialValueRef.current));\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [key]);\r\n\r\n return [storedValue, setValue, removeValue] as const;\r\n}\r\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@usefy/use-local-storage",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "A React hook for persisting state in localStorage with automatic synchronization",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
24
|
+
"@testing-library/react": "^16.3.1",
|
|
25
|
+
"@testing-library/user-event": "^14.6.1",
|
|
26
|
+
"@types/react": "^19.0.0",
|
|
27
|
+
"jsdom": "^27.3.0",
|
|
28
|
+
"react": "^19.0.0",
|
|
29
|
+
"rimraf": "^6.0.1",
|
|
30
|
+
"tsup": "^8.0.0",
|
|
31
|
+
"typescript": "^5.0.0",
|
|
32
|
+
"vitest": "^4.0.16"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/geon0529/usefy.git",
|
|
40
|
+
"directory": "packages/use-local-storage"
|
|
41
|
+
},
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"keywords": [
|
|
44
|
+
"react",
|
|
45
|
+
"hooks",
|
|
46
|
+
"localStorage",
|
|
47
|
+
"storage",
|
|
48
|
+
"state",
|
|
49
|
+
"persistence"
|
|
50
|
+
],
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsup",
|
|
53
|
+
"dev": "tsup --watch",
|
|
54
|
+
"test": "vitest run",
|
|
55
|
+
"test:watch": "vitest",
|
|
56
|
+
"typecheck": "tsc --noEmit",
|
|
57
|
+
"clean": "rimraf dist"
|
|
58
|
+
}
|
|
59
|
+
}
|