[typescript] useLocalStorage 커스텀 훅 만들어서 쓰기
2024. 11. 25. 13:00
반응형
// useLocalStorage.ts
import { useState, useEffect, useCallback } from 'react';
function useLocalStorage<T>(key: string, initialValue?: T) {
const [storedValue, setStoredValue] = useState<T | undefined>(() => {
if (typeof window === 'undefined') {
return initialValue;
}
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(`Error reading localStorage key “${key}”:`, error);
return initialValue;
}
});
// Update localStorage when the value changes
const setValue = useCallback(
(value: T | ((prev: T | undefined) => T)) => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
if (typeof window !== 'undefined') {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
// Trigger a custom storage event for React context sync
window.dispatchEvent(
new StorageEvent('storage', {
key,
newValue: JSON.stringify(valueToStore),
}),
);
}
} catch (error) {
console.error(`Error setting localStorage key “${key}”:`, error);
}
},
[key, storedValue],
);
const removeValue = useCallback(() => {
try {
if (typeof window !== 'undefined') {
window.localStorage.removeItem(key);
}
setStoredValue(undefined);
} catch (error) {
console.error(`Error removing localStorage key “${key}”:`, error);
}
}, [key]);
// Listen for storage changes
useEffect(() => {
const handleStorageChange = (event: StorageEvent) => {
if (event.key === key) {
try {
const newValue = event.newValue
? JSON.parse(event.newValue)
: undefined;
setStoredValue(newValue);
} catch (error) {
console.error(`Error parsing localStorage key “${key}”:`, error);
}
}
};
window.addEventListener('storage', handleStorageChange);
return () => {
window.removeEventListener('storage', handleStorageChange);
};
}, [key]);
return { storedValue, setValue, removeValue } as const;
}
export default useLocalStorage;
// 외부에서 가져다 쓰는 컴포넌트 예시
...
const { setValue, storedValue } = useLocalStorage<ValuesType>('sell');
const handleClick = (input : string) => {
setValue((prev) => ({ ...prev, phoneNumber: input }));
};
hook 안의 코드에서 EventListener와 dispatchEvent를 달아놨기 때문에,
localStorage 값이 업데이트 됐을 때 화면단도 같이 씽크를 맞춰 잘 바뀐다.
반응형
'한 걸음 > TS & JS' 카테고리의 다른 글
[typescript 환경 구축] OpenAPI Generator와 함께 타입스크립트를 편리하게 사용해보자 (0) | 2024.05.21 |
---|---|
[정규식] front-side 검색 시, 대소문자 구분없이 찾아주기 (0) | 2023.10.27 |
[axios] 객체를 multipart/form-data으로 보내기 (0) | 2023.09.19 |
Object.fromEntries()와 Object.entries() (0) | 2023.09.04 |
lodash isEqual, mapValues (0) | 2023.08.29 |