useSessionStorage.tsx 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  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, initialValue: T) {
  5. const value = sessionStorage.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. function useSessionStorage<T>(
  21. key: string,
  22. initialValue?: T
  23. ): [T | undefined, (value: T | undefined) => void, () => void] {
  24. const [state, setState] = useState<T | undefined>(() =>
  25. readStorageValue(key, initialValue)
  26. );
  27. useEffect(() => {
  28. setState(readStorageValue(key, initialValue));
  29. // We want to re-initialized the storage value only when the key changes.
  30. // eslint-disable-next-line react-hooks/exhaustive-deps
  31. }, [key]);
  32. const wrappedSetState = useCallback(
  33. (value: T | undefined) => {
  34. setState(value);
  35. try {
  36. sessionStorageWrapper.setItem(key, JSON.stringify(value));
  37. } catch {
  38. // Best effort and just update the in-memory value.
  39. }
  40. },
  41. [key]
  42. );
  43. const removeItem = useCallback(() => {
  44. setState(undefined);
  45. sessionStorageWrapper.removeItem(key);
  46. }, [key]);
  47. if (!isBrowser) {
  48. return [initialValue, () => {}, () => {}];
  49. }
  50. return [state, wrappedSetState, removeItem];
  51. }
  52. export default useSessionStorage;