Add useStorageState hook (#37825)
This commit is contained in:
1 parent
bbd88d356d
commit
f99c60a8f3
2 files changed
+80
-13
No files matched your search
@@ -1,9 +1,14 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
interface StorageOptions {
|
||||
type?: 'local' | 'session';
|
||||
prefix?: string;
|
||||
}
|
||||
|
||||
export function useStorage({
|
||||
type = 'local',
|
||||
prefix = '',
|
||||
}: { type?: 'local' | 'session'; prefix?: string } = {}) {
|
||||
}: StorageOptions = {}) {
|
||||
const storageType = type === 'local' ? 'localStorage' : 'sessionStorage';
|
||||
const isAvailable = useMemo(
|
||||
() => storageAvailable(storageType),
|
||||
@@ -23,6 +28,7 @@ export function useStorage({
|
||||
},
|
||||
[isAvailable, storageType, prefix],
|
||||
);
|
||||
|
||||
const setItem = useCallback(
|
||||
(key: string, value: string) => {
|
||||
if (!isAvailable) {
|
||||
@@ -35,13 +41,52 @@ export function useStorage({
|
||||
[isAvailable, storageType, prefix],
|
||||
);
|
||||
|
||||
const removeItem = useCallback(
|
||||
(key: string) => {
|
||||
if (!isAvailable) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
window[storageType].removeItem(prefix ? `${prefix};${key}` : key);
|
||||
} catch {}
|
||||
},
|
||||
[isAvailable, storageType, prefix],
|
||||
);
|
||||
|
||||
return {
|
||||
isAvailable,
|
||||
getItem,
|
||||
setItem,
|
||||
removeItem,
|
||||
};
|
||||
}
|
||||
|
||||
export function useStorageState<T extends string | boolean>(
|
||||
key: string,
|
||||
initialState: T,
|
||||
options?: StorageOptions,
|
||||
) {
|
||||
const { getItem, setItem, removeItem } = useStorage(options);
|
||||
const [state, setState] = useState<T>(
|
||||
() => (retrieveBooleanOrString(getItem(key)) as T | null) ?? initialState,
|
||||
);
|
||||
|
||||
const handleSetState = useCallback(
|
||||
(newValue: T) => {
|
||||
setItem(key, castToString(newValue));
|
||||
setState(newValue);
|
||||
},
|
||||
[key, setItem],
|
||||
);
|
||||
|
||||
const removeState = useCallback(() => {
|
||||
removeItem(key);
|
||||
setState(initialState);
|
||||
}, [initialState, key, removeItem]);
|
||||
|
||||
return [state, handleSetState, removeState] as const;
|
||||
}
|
||||
|
||||
// Tests the storage availability for the given type. Taken from MDN:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
|
||||
export function storageAvailable(type: 'localStorage' | 'sessionStorage') {
|
||||
@@ -62,3 +107,21 @@ export function storageAvailable(type: 'localStorage' | 'sessionStorage') {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function castToString(value: string | boolean) {
|
||||
if (typeof value === 'boolean') {
|
||||
return value ? '1' : '0';
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
function retrieveBooleanOrString(value: string | null) {
|
||||
if (value === '1') {
|
||||
return true;
|
||||
} else if (value === '0') {
|
||||
return false;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user