import{Dispatch, SetStateAction, useCallback, useEffect, useState}from'react';// See: https://usehooks-ts.com/react-hook/use-event-listenerimport{useEventListener}from'../useEventListener';
declare global {interfaceWindowEventMap{'local-storage': CustomEvent;}}
type SetValue<T>= Dispatch<SetStateAction<T>>;function useLocalStorage<T>(key: string,initialValue:T):[T, SetValue<T>]{// Get from local storage then// parse stored json or return initialValueconst readValue =useCallback(():T=>{// Prevent build error "window is undefined" but keep keep workingif(typeof window ==='undefined'){return initialValue;}try{const item = window.localStorage.getItem(key);return item ?(parseJSON(item)asT): initialValue;}catch(error){
console.warn(`Error reading localStorage key “${key}”:`, error);return initialValue;}},[initialValue, key]);// State to store our value// Pass initial state function to useState so logic is only executed onceconst[storedValue, setStoredValue]= useState<T>(readValue);// Return a wrapped version of useState's setter function that ...// ... persists the new value to localStorage.constsetValue: SetValue<T>=useCallback((value)=>{// Prevent build error "window is undefined" but keeps workingif(typeof window =='undefined'){
console.warn(`Tried setting localStorage key “${key}” even though environment is not a client`);}try{// Allow value to be a function so we have the same API as useStateconst newValue = value instanceofFunction?value(storedValue): value;// Save to local storage
window.localStorage.setItem(key,JSON.stringify(newValue));// Save statesetStoredValue(newValue);// We dispatch a custom event so every useLocalStorage hook are notified
window.dispatchEvent(newEvent('local-storage'));}catch(error){
console.warn(`Error setting localStorage key “${key}”:`, error);}},[key, storedValue],);useEffect(()=>{setStoredValue(readValue());// eslint-disable-next-line react-hooks/exhaustive-deps},[]);const handleStorageChange =useCallback(()=>{setStoredValue(readValue());},[readValue]);// this only works for other documents, not the current oneuseEventListener('storage', handleStorageChange);// this is a custom event, triggered in writeValueToLocalStorage// See: useLocalStorage()useEventListener('local-storage', handleStorageChange);return[storedValue, setValue];}exportdefault useLocalStorage;// A wrapper for "JSON.parse()"" to support "undefined" valuefunction parseJSON<T>(value: string |null):T|undefined{try{return value ==='undefined'?undefined:JSON.parse(value ??'');}catch{
console.log('parsing error on',{value});returnundefined;}}