useLocalStorage
Introduction
이 훅을 함수형 컴포넌트에서 사용하여 특정 키에 대한 로컬 스토리지를 관리할 수 있습니다. 이 훅의 사용 목적으로는 다음과 같습니다.
로컬 스토리지 관리의 추상화:
useLocalStorage훅은 로컬 스토리지와 관련된 복잡한 작업을 추상화하고 간소화합니다. 이를 통해 컴포넌트에서 간편하게 로컬 스토리지를 다룰 수 있습니다.
리액트 상태와의 통합:
훅은
useState를 사용하여 로컬 스토리지의 값을 리액트 상태로 관리합니다. 이는 컴포넌트의 상태를 업데이트하면서 로컬 스토리지도 동기화되어 사용자 인터페이스가 실시간으로 반응할 수 있습니다.
캡슐화와 재사용성:
로컬 스토리지와 관련된 로직이 훅에 캡슐화되어 있기 때문에, 이 훅을 다른 컴포넌트에서 간단히 재사용할 수 있습니다. 이로써 중복 코드를 방지하고 일관된 로컬 스토리지 관리를 할 수 있습니다.
이벤트 핸들링 및 상태 업데이트:
update함수를 사용하여 로컬 스토리지 값이 다른 탭이나 창에서 변경되었을 때 실시간으로 상태를 업데이트할 수 있습니다. 이로써 다양한 탭 간에 데이터 동기화를 달성할 수 있습니다.
서버 사이드 렌더링(SSR) 대응:
훅은 서버 환경에서 실행될 때 로컬 스토리지에 접근하는 문제를 방지합니다. SSR 환경에서 안전하게 사용할 수 있도록 구현되어 있습니다.
옵션 설정으로 초기값 관리:
옵션을 통해 초기값을 로컬 스토리지에 저장할지 여부를 관리할 수 있습니다. 이는 특정 키에 대한 초기값을 설정하고, 로컬 스토리지에 해당 키의 값이 없을 때 초기값을 저장할 수 있습니다.
Example
const MyComponent = () => {
const { read, save, remove, update } = useLocalStorage("myKey", "default-value", { initialSave: true });
useEffect(() => {
// 로컬 스토리지가 변경될 때 동작을 수행
update();
}, []);
return (
<div>
<p>저장된 값: {read()}</p>
<button onClick={() => save("new-value")}>로컬 스토리지에 저장</button>
<button onClick={remove}>로컬 스토리지에서 삭제</button>
</div>
);
};이 훅은 React 컴포넌트에서 로컬 스토리지 작업을 편리하게 관리할 수 있도록 도와줍니다.
Hook
import type { Dispatch, SetStateAction } from "react";
import { useCallback, useEffect, useState } from "react";
type SetValue<T> = Dispatch<SetStateAction<T>>;
interface Options {
initialSave: boolean;
}
const isServer = typeof window === "undefined";
/**
* 이 훅은 로컬스토리지를 관리하는 커스텀 훅 입니다.
* 기본적으로 로컬스토리지의 값을 읽기, 저장, 삭제, 업데이트 등의 기능을 제공하고 있습니다.
* @param {string} key - 로컬 스토리지의 Key
* @param {T} initialValue - 로컬 스토리지의 초깃값
* @param {Options} options - 훅에서 쓰이는 옵션 값
* @returns {()=>{}} read(읽기), save(저장), remove(삭제), update(업데이트 마운트)
*/
/**
*
* @param options
* @description options의 기능에 대한 설명
* initialSave : 스토리지에 저장된 값이 없을 경우, 초기값을 저장할 것인지 말 것인지 type : boolean
*/
export default function useLocalStorage<T>(key: string, initialValue: T | (() => T), options: Options = { initialSave: false }) {
const [storedValue, setStoredValue] = useState<T>(initialValue);
const isStorageEvent = (event: StorageEvent | CustomEvent): event is StorageEvent => {
return "key" in event;
};
/** 로컬 스토리지 읽기 */
const readValueFromLocalStorage = (): T => {
const initialValueToUse = initialValue instanceof Function ? initialValue() : initialValue;
// SSR에서 발생할 수 있는 오류 방지하기 위해 설정. window 객체가 존재하지 않을때, localStorage에 접근 하는 것을 방지
if (isServer) {
return initialValueToUse;
}
try {
const rawData = window.localStorage.getItem(key) as T;
/** 값이 없을 경우 */
if (typeof rawData === "object" && rawData === null && options.initialSave) {
save(initialValueToUse);
return initialValueToUse;
}
return rawData ? rawData : initialValueToUse;
} catch {
console.warn(`로컬 스토리지를 가져오는 것에 실패하였습니다. 키 : "${key}", 값 : error `);
return initialValueToUse;
}
};
// read함수 메모이제이션
const read = useCallback<() => T>(() => {
return readValueFromLocalStorage();
}, []);
useEffect(() => {
setStoredValue(read());
}, [key]);
/** 로컬 스토리지 읽기 */
/** 로컬 스토리지 저장 */
const saveValueFromLocalStorage = (value: T) => {
if (isServer) {
console.warn("브라우저 환경에서만 사용 가능합니다. 서버환경에서 사용이 불가능합니다.");
return undefined;
}
try {
setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value));
return value;
} catch (error) {
if (error instanceof DOMException && error.name === "QuotaExceededError") {
console.error("실패 : 로컬 스토리지 용량이 부족합니다.");
} else {
console.warn(`로컬 스토리지에 값을 저장하는 데 실패했습니다. 키: "${key}"`);
}
}
};
const save: SetValue<T> = useCallback(async (value: T) => {
return await saveValueFromLocalStorage(value);
}, []);
/** 로컬 스토리지 저장 */
/** 로컬 스토리지 변화에 따른 상태관리 감지 */
const update = useCallback(
(event: StorageEvent | CustomEvent) => {
if (isStorageEvent(event) && event.key !== key) return;
setStoredValue(read());
},
[key, read]
);
/** 로컬 스토리지 변화에 따른 상태관리 감지 */
/** 로컬 스토리지 삭제 */
const remove = () => {
if (isServer) {
console.warn("현재 브라우저 환경이 아닙니다.");
return key;
}
try {
window.localStorage.removeItem(key);
setStoredValue(undefined);
} catch (error) {
console.warn(`로컬 스토리지에서 항목을 삭제하는 데 실패했습니다. 키: "${key}"`);
return;
}
};
return { read, save, remove, update };
}이 훅은 React 애플리케이션에서 로컬 스토리지를 관리하기 위한 커스텀 React 훅인 useLocalStorage을 정의합니다. 이 훅은 로컬 스토리지에서 값 읽기, 저장하기, 업데이트하기, 삭제하기 등의 기능을 제공합니다.
주요 구성 요소를 살펴보겠습니다:
타입 정의:
SetValue<T>:T타입의 상태를 설정하는 함수를 나타내는 타입.Options: 훅에 대한 구성 옵션을 정의하는 인터페이스.
훅 구현:
훅은 세 개의 매개변수를 받습니다:
key: 로컬 스토리지에 데이터를 저장할 키를 나타내는 문자열.initialValue: 로컬 스토리지에 데이터가 없을 때 사용할 초기값.options: 훅의 구성 옵션을 나타내는 선택적 매개변수.
이 훅은 로컬 스토리지에서 데이터를 읽기, 저장하기, 업데이트하기 및 삭제하기 위한 메서드를 가진 객체를 반환합니다.
기능:
훅은 서버 환경(SSR)에서 실행 중인지 확인하여
window및 로컬 스토리지에 액세스하는 데 잠재적인 문제를 방지합니다.useState훅을 사용하여 저장된 값의 상태를 관리합니다.readValueFromLocalStorage함수는 로컬 스토리지에서 값을 읽는 역할을 합니다. 값이 없고initialSave옵션이true로 설정된 경우 초기값을 로컬 스토리지에 저장합니다.read함수는readValueFromLocalStorage의 메모이제이션된 버전입니다.useEffect훅은key가 변경될 때마다 상태를 업데이트합니다.saveValueFromLocalStorage함수는 제공된 값을 로컬 스토리지에 저장하고 상태를 업데이트합니다.save함수는saveValueFromLocalStorage의 메모이제이션된 버전입니다.update함수는 로컬 스토리지의 변경(다른 탭이나 창에서 발생)을 처리하고 상태를 업데이트합니다.remove함수는 로컬 스토리지에서 항목을 삭제하고 상태를undefined로 설정합니다.
Last updated