useSessionStorage.tsx 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import {useCallback, useEffect, useState} from 'react';
  2. import sessionStorageWrapper from 'sentry/utils/sessionStorage';
  3. const isBrowser = typeof window !== 'undefined';
  4. function readStorageValue<T>(key: string, initialValue: T) {
  5. const value = sessionStorageWrapper.getItem(key);
  6. // We check for 'undefined' because the value may have
  7. // previously been serialized as 'undefined'. This should no longer
  8. // happen, but want to handle it gracefully.
  9. if (value === null || value === 'undefined') {
  10. return initialValue;
  11. }
  12. // Try parse storage value.
  13. try {
  14. return JSON.parse(value);
  15. } catch {
  16. // If parsing fails, return initial value.
  17. return initialValue;
  18. }
  19. }
  20. export function useSessionStorage<T>(
  21. key: string,
  22. initialValue: T
  23. ): [T, (value: T) => void, () => void] {
  24. const [state, setState] = useState<T>(() => readStorageValue(key, initialValue));
  25. useEffect(() => {
  26. setState(readStorageValue(key, initialValue));
  27. // We want to re-initialized the storage value only when the key changes.
  28. // eslint-disable-next-line react-hooks/exhaustive-deps
  29. }, [key]);
  30. const wrappedSetState = useCallback(
  31. (value: T) => {
  32. setState(value);
  33. try {
  34. sessionStorageWrapper.setItem(key, JSON.stringify(value));
  35. } catch {
  36. // Best effort and just update the in-memory value.
  37. }
  38. },
  39. [key]
  40. );
  41. const removeItem = useCallback(() => {
  42. setState(initialValue);
  43. sessionStorageWrapper.removeItem(key);
  44. }, [key, initialValue]);
  45. if (!isBrowser) {
  46. return [initialValue, () => {}, () => {}];
  47. }
  48. return [state, wrappedSetState, removeItem];
  49. }