UNPKG

@modern-kit/react

Version:
1 lines 10.3 kB
{"version":3,"file":"index.mjs","sources":["../../../src/hooks/useLocalStorage/useLocalStorage.utils.ts","../../../src/hooks/useLocalStorage/index.ts"],"sourcesContent":["import { parseJSON } from '@modern-kit/utils';\n\nconst CUSTOM_EVENT_KEYS = 'modern-kit-local-storage';\n\nexport const localStorageEventHandler = {\n key: CUSTOM_EVENT_KEYS,\n subscribe: (callback: () => void) => {\n window.addEventListener(CUSTOM_EVENT_KEYS, callback);\n },\n unsubscribe: (callback: () => void) => {\n window.removeEventListener(CUSTOM_EVENT_KEYS, callback);\n },\n dispatchEvent: () => {\n window.dispatchEvent(new StorageEvent(CUSTOM_EVENT_KEYS));\n },\n};\n\nexport const getSnapshot = (key: string) => {\n try {\n return window.localStorage.getItem(key);\n } catch {\n return null;\n }\n};\n\n// SSR 환경에서 initialValue를 반환\nexport const getServerSnapshot = <T>(initialValue: T | null) => {\n return JSON.stringify(initialValue);\n};\n\nexport const subscribe = (callback: () => void) => {\n localStorageEventHandler.subscribe(callback);\n return () => {\n localStorageEventHandler.unsubscribe(callback);\n };\n};\n\nexport const getParsedState = <T>(\n state: string | null,\n fallbackValue: T | null\n) => {\n if (state == null) {\n return fallbackValue;\n }\n return parseJSON<T>(state);\n};\n","import { isFunction } from '@modern-kit/utils';\nimport {\n Dispatch,\n SetStateAction,\n useCallback,\n useMemo,\n useSyncExternalStore,\n} from 'react';\nimport {\n getParsedState,\n getServerSnapshot,\n getSnapshot,\n localStorageEventHandler,\n subscribe,\n} from './useLocalStorage.utils';\nimport { useVisibilityChange } from '../useVisibilityChange';\nimport { StorageManager } from '@modern-kit/utils';\n\nconst storageManager = new StorageManager('localStorage');\n\ninterface UseLocalStorageWithoutInitialValueOptions {\n key: string;\n visibilityChange?: boolean;\n}\n\ninterface UseLocalStorageWithInitialValueOptions<T> {\n key: string;\n initialValue: T | (() => T);\n visibilityChange?: boolean;\n}\n\ntype UseLocalStorageOptions<T> =\n | UseLocalStorageWithoutInitialValueOptions\n | UseLocalStorageWithInitialValueOptions<T>;\n\n/**\n * @description `useLocalStorage` 훅은 지정된 `key`를 사용하여 `localStorage`에 데이터를 저장하고 불러오는 기능을 제공합니다.\n *\n * @template T - `state`의 데이터 타입입니다.\n *\n * @param {UseLocalStorageWithInitialValueOptions<T>} options - initialValue를 포함한 useLocalStorage 훅의 속성입니다.\n * @param {string} options.key - `localStorage`에서 데이터를 저장하고 가져올 때 사용하는 키입니다. 필수 속성입니다.\n * @param {T | (() => T)} options.initialValue - `state`의 초기 값을 설정합니다. 함수로 전달할 경우 함수의 반환값이 초기 값으로 사용됩니다.\n * @param {boolean} [options.visibilityChange=false] - 브라우저 탭의 가시성 변경 이벤트를 감지하여 가시성 상태가 되면 `state`를 동기화합니다. 사용 케이스로 `sessionStorage`와 다르게 탭 간 공유되는 저장소이기 때문에 탭 간 동기화가 필요할 때 사용합니다.\n *\n * @returns {{\n * state: T;\n * setState: Dispatch<SetStateAction<T>>;\n * removeState: () => void;\n * }}\n * - `state`: 현재 `localStorage`에 저장된 값입니다. 값이 없을 경우 initialValue로 초기화됩니다.\n * - `setState`: `localStorage`에 저장된 값을 업데이트합니다. 새로운 값 또는 이전 상태를 인자로 받는 함수를 전달할 수 있습니다.\n * - `removeState`: `localStorage`에서 해당 `key`의 값을 삭제합니다.\n *\n * @example\n * const { state, setState, removeState } = useLocalStorage<string>({\n * key: 'username',\n * initialValue: 'Guest',\n * });\n *\n * state; // string\n */\nexport function useLocalStorage<T>({\n key,\n initialValue,\n visibilityChange,\n}: UseLocalStorageWithInitialValueOptions<T>): {\n state: T;\n setState: Dispatch<SetStateAction<T>>;\n removeState: () => void;\n};\n\n/**\n * @description `useLocalStorage` 훅은 지정된 `key`를 사용하여 `localStorage`에 데이터를 저장하고 불러오는 기능을 제공합니다.\n *\n * @template T - `state`의 데이터 타입입니다.\n *\n * @param {UseLocalStorageWithoutInitialValueOptions} options - initialValue가 없는 useLocalStorage 훅의 속성입니다.\n * @param {string} options.key - `localStorage`에서 데이터를 저장하고 가져올 때 사용하는 키입니다. 필수 속성입니다.\n * @param {boolean} [options.visibilityChange=false] - 브라우저 탭의 가시성 변경 이벤트를 감지하여 가시성 상태가 되면 `state`를 동기화합니다.\n * 사용 케이스로 `sessionStorage`와 다르게 탭 간 공유되는 저장소이기 때문에 탭 간 동기화가 필요할 때 사용합니다.\n *\n * @returns {{\n * state: T | null;\n * setState: Dispatch<SetStateAction<T | null>>;\n * removeState: () => void;\n * }}\n * - `state`: 현재 `localStorage`에 저장된 값입니다. 값이 없을 경우 `null`을 반환합니다.\n * - `setState`: `localStorage`에 저장된 값을 업데이트합니다. 새로운 값 또는 이전 상태를 인자로 받는 함수를 전달할 수 있습니다.\n * - `removeState`: `localStorage`에서 해당 `key`의 값을 삭제합니다.\n *\n * @example\n * const { state, setState, removeState } = useLocalStorage<string>({\n * key: 'username',\n * });\n *\n * state; // string | null\n */\nexport function useLocalStorage<T = unknown>({\n key,\n visibilityChange,\n}: UseLocalStorageWithoutInitialValueOptions): {\n state: T | null;\n setState: Dispatch<SetStateAction<T | null>>;\n removeState: () => void;\n};\n\nexport function useLocalStorage<T>(options: UseLocalStorageOptions<T>) {\n const { key, visibilityChange = false } = options;\n const initialValue = 'initialValue' in options ? options.initialValue : null;\n\n const initialValueToUse = useMemo(() => {\n return isFunction(initialValue) ? initialValue() : initialValue;\n }, [initialValue]);\n\n const externalStoreState = useSyncExternalStore(\n subscribe,\n () => getSnapshot(key),\n () => getServerSnapshot(initialValueToUse)\n );\n\n const state = useMemo(() => {\n return getParsedState<T>(externalStoreState, initialValueToUse);\n }, [externalStoreState, initialValueToUse]);\n\n const setState = useCallback(\n (value: SetStateAction<T | null>) => {\n try {\n const prevStateString = getSnapshot(key);\n const prevState = getParsedState<T>(prevStateString, initialValueToUse);\n const valueToUse = isFunction(value) ? value(prevState) : value;\n\n storageManager.setItem(key, valueToUse);\n localStorageEventHandler.dispatchEvent();\n } catch (err) {\n throw new Error(\n `로컬 스토리지 \"${key}\" key에 데이터를 저장하는데 실패했습니다: ${err}`\n );\n }\n },\n [key, initialValueToUse]\n );\n\n const removeState = useCallback(() => {\n try {\n storageManager.removeItem(key);\n localStorageEventHandler.dispatchEvent();\n } catch (err) {\n throw new Error(\n `로컬 스토리지 \"${key}\" key의 데이터를 삭제하는데 실패했습니다: ${err}`\n );\n }\n }, [key]);\n\n const handleVisibilityChange = useCallback(() => {\n localStorageEventHandler.dispatchEvent();\n }, []);\n\n useVisibilityChange({\n onShow: handleVisibilityChange,\n enabled: visibilityChange,\n });\n\n return { state, setState, removeState };\n}\n"],"names":[],"mappings":"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"}