123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- import {useCallback, useLayoutEffect, useRef, useState} from 'react';
- import localStorageWrapper from 'sentry/utils/localStorage';
- const SUPPORTS_QUEUE_MICROTASK = window && 'queueMicrotask' in window;
- const SUPPORTS_LOCAL_STORAGE = window && 'localStorage' in window;
- function scheduleMicroTask(callback: () => void) {
- if (SUPPORTS_QUEUE_MICROTASK) {
- window.queueMicrotask(callback);
- } else {
- Promise.resolve()
- .then(callback)
- .catch(e => {
-
- if (window) {
- window.setTimeout(() => {
- throw e;
- });
- } else {
-
- throw e;
- }
- });
- }
- }
- function tryParseStorage<T>(jsonEncodedValue: string): T | null {
- try {
- return JSON.parse(jsonEncodedValue);
- } catch (e) {
- return null;
- }
- }
- function makeTypeExceptionString(instance: string) {
- return `useLocalStorage: Native serialization of ${instance} is not supported. You are attempting to serialize a ${instance} instance this data will be lost. For more info, see how ${instance.toLowerCase()}s are serialized https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#examples`;
- }
- function strictReplacer<T>(_key: string, value: T): T {
- if (typeof BigInt !== 'undefined' && typeof value === 'bigint') {
- throw new TypeError(makeTypeExceptionString('BigInt'));
- }
- if (value instanceof RegExp) {
- throw new TypeError(makeTypeExceptionString('RegExp'));
- }
- if (typeof Map !== 'undefined' && value instanceof Map) {
- throw new TypeError(makeTypeExceptionString('Map'));
- }
- if (typeof Set !== 'undefined' && value instanceof Set) {
- throw new TypeError(makeTypeExceptionString('Set'));
- }
- if (typeof WeakMap !== 'undefined' && value instanceof WeakMap) {
- throw new TypeError(makeTypeExceptionString('WeakMap'));
- }
- if (typeof WeakSet !== 'undefined' && value instanceof WeakSet) {
- throw new TypeError(makeTypeExceptionString('WeakSet'));
- }
- return value;
- }
- function stringifyForStorage(value: unknown) {
- return JSON.stringify(value, strictReplacer, 0);
- }
- function defaultOrInitializer<S>(
- defaultValueOrInitializeFn: S | ((value?: unknown, rawStorageValue?: unknown) => S),
- value?: unknown,
- rawValue?: unknown
- ): S {
- if (typeof defaultValueOrInitializeFn === 'function') {
-
-
- return defaultValueOrInitializeFn(value, rawValue);
- }
- return value === undefined ? defaultValueOrInitializeFn : (value as S);
- }
- function initializeStorage<S>(
- key: string,
- defaultValueOrInitializeFn: S | ((rawStorageValue?: unknown) => S)
- ): S {
- if (typeof key !== 'string') {
- throw new TypeError('useLocalStorage: key must be a string');
- }
-
-
- if (!SUPPORTS_LOCAL_STORAGE) {
- return defaultOrInitializer(defaultValueOrInitializeFn, undefined, null);
- }
-
- const jsonEncodedValue = localStorageWrapper.getItem(key);
- if (jsonEncodedValue === null) {
- return defaultOrInitializer(defaultValueOrInitializeFn, undefined, null);
- }
-
- const decodedValue = tryParseStorage<S>(jsonEncodedValue);
- if (decodedValue === null) {
- return defaultOrInitializer(defaultValueOrInitializeFn, undefined, jsonEncodedValue);
- }
-
- return defaultOrInitializer(defaultValueOrInitializeFn, decodedValue, jsonEncodedValue);
- }
- export function useLocalStorageState<S>(
- key: string,
- initialState: S | ((value?: unknown, rawValue?: unknown) => S)
- ): [S, (value: S) => void] {
- const [value, setValue] = useState(() => {
- return initializeStorage<S>(key, initialState);
- });
-
-
-
- const renderRef = useRef(false);
- useLayoutEffect(() => {
- if (!renderRef.current) {
- renderRef.current = true;
- return;
- }
- setValue(initializeStorage(key, initialState));
-
-
- }, [key]);
- const setStoredValue = useCallback(
- (newValue: S) => {
- if (typeof key !== 'string') {
- throw new TypeError('useLocalStorage: key must be a string');
- }
- setValue(newValue);
-
-
- scheduleMicroTask(() => {
- localStorageWrapper.setItem(key, stringifyForStorage(newValue));
- });
- },
- [key]
- );
- return [value, setStoredValue];
- }
|