Last active
August 23, 2024 12:11
-
-
Save saulodias/268ff05763ca54046b44b49c83b01034 to your computer and use it in GitHub Desktop.
A TypeScript module with useSessionStorage and useLocalStorage React hooks to save values in the browser sessionStorage or localStorage.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState, useEffect } from 'react' | |
// Check if the code is running in the browser (Next.js support) | |
const isClient = typeof window !== 'undefined' | |
type StorageType = 'localStorage' | 'sessionStorage' | |
/** | |
* A prefix to identify session and local storage keys saved using | |
* the storage hooks in this application. | |
*/ | |
export const STORAGE_KEYS_PREFIX = 'my-app_' | |
/** | |
* Interface for a JSON converter which provides methods to serialize | |
* and deserialize values to and from JSON strings. | |
*/ | |
export interface JsonConverter<AppType, ParsedType> { | |
/** | |
* Serializes a value to a JSON-compatible object. | |
* @param value The value to be serialized. | |
* @returns The JSON-compatible object representation of the value. | |
*/ | |
toJson: (value: AppType) => ParsedType | |
/** | |
* Deserializes a JSON-compatible object to a value. | |
* @param storedValue The JSON-compatible object to be deserialized. | |
* @returns The deserialized value. | |
*/ | |
fromJson: (storedValue: ParsedType) => AppType | |
} | |
const storageFactory = | |
(storageType: StorageType, keyPrefix: string) => | |
<AppType, ParsedType = AppType>( | |
storageKey: string, | |
fallbackState: AppType, | |
converter?: JsonConverter<AppType, ParsedType> | |
): [AppType, React.Dispatch<React.SetStateAction<AppType>>] => { | |
const storage: Storage | null = isClient ? window[storageType] : null | |
if (!storageKey) throw new Error(`"storageKey" must be a nonempty string, but "${storageKey}" was passed.`) | |
const [value, setValue] = useState<AppType>(() => { | |
if (!storage) return fallbackState | |
const storedString = storage.getItem(keyPrefix + storageKey) | |
if (storedString && converter) { | |
const parsedValue = JSON.parse(storedString) | |
return converter.fromJson(parsedValue) | |
} else if (storedString) { | |
return JSON.parse(storedString) // If no converter provided, return the parsed JSON directly | |
} else { | |
return fallbackState | |
} | |
}) | |
useEffect(() => { | |
if (!storage) return | |
if (converter) { | |
const jsonValue = converter.toJson(value) | |
storage.setItem(keyPrefix + storageKey, JSON.stringify(jsonValue)) | |
} else { | |
storage.setItem(keyPrefix + storageKey, JSON.stringify(value)) | |
} | |
}, [value, storageKey, converter]) | |
return [value, setValue] | |
} | |
/** | |
* Saves data in local storage. | |
* @param storageKey A string to identify the value being cached. | |
* @param fallbackState The default value when no value has been stored yet. | |
* @returns A stateful value, and a function to update it. | |
* @example | |
* const [collapsed, setCollapsed] = useLocalStorage('isSidebarCollapsed', false); | |
*/ | |
const useLocalStorage = storageFactory('localStorage', STORAGE_KEYS_PREFIX) | |
/** | |
* Saves data in session storage. | |
* @param storageKey A string to identify the value being cached. | |
* @param fallbackState The default value when no value has been stored yet. | |
* @returns A stateful value, and a function to update it. | |
* @example | |
* const [collapsed, setCollapsed] = useSessionStorage('isSidebarCollapsed', false); | |
*/ | |
const useSessionStorage = storageFactory('sessionStorage', STORAGE_KEYS_PREFIX) | |
export { useLocalStorage, useSessionStorage } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment