Skip to content

Commit

Permalink
Fix #2773: Add useStorage hook (#2774)
Browse files Browse the repository at this point in the history
  • Loading branch information
melloware authored Apr 20, 2022
1 parent 1dc89f5 commit 24d64e5
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
4 changes: 3 additions & 1 deletion components/lib/hooks/Hooks.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DependencyList, EffectCallback, Ref } from 'react';
import { Dispatch, DependencyList, EffectCallback, Ref } from 'react';

export type TargetType = 'document' | 'window' | Ref<HTMLElement> | undefined;
export type StorageType = 'local' | 'session';

interface EventOptions {
target?: TargetType;
Expand Down Expand Up @@ -31,3 +32,4 @@ export declare function useOverlayScrollListener(options: EventOptions): any[];
export declare function useResizeListener(options: ResizeEventOptions): any[];
export declare function useInterval(fn: any, delay?: number, when?: boolean): any[];
export declare function useTimeout(fn: any, delay?: number, when?: boolean): any[];
export declare function useStorage<S>(initialValue: S, key: string, storage?: StorageType): [S, Dispatch<SetStateAction<S>>];
3 changes: 2 additions & 1 deletion components/lib/hooks/Hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useOverlayListener } from './useOverlayListener';
import { useOverlayScrollListener } from './useOverlayScrollListener';
import { useResizeListener } from './useResizeListener';
import { useInterval } from './useInterval';
import { useStorage } from './useStorage';
import { useTimeout } from './useTimeout';

export { usePrevious, useMountEffect, useUpdateEffect, useUnmountEffect, useEventListener, useOverlayListener, useOverlayScrollListener, useResizeListener, useInterval, useTimeout };
export { usePrevious, useMountEffect, useUpdateEffect, useUnmountEffect, useEventListener, useOverlayListener, useOverlayScrollListener, useResizeListener, useInterval, useStorage, useTimeout };
51 changes: 51 additions & 0 deletions components/lib/hooks/useStorage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* eslint-disable */
import * as React from 'react';

/**
* Hook to wrap around useState that stores the value in the browser local/session storage.
*
* @param {any} initialValue the initial value to store
* @param {string} key the key to store the value in local/session storage
* @param {string} storage either 'local' or 'session' for what type of storage
* @returns a stateful value, and a function to update it.
*/
export const useStorage = (initialValue, key, storage = 'local') => {

// Since the local storage API isn't available in server-rendering environments,
// we check that typeof window !== 'undefined' to make SSR and SSG work properly.
const storageAvailable = typeof window !== 'undefined';

const [storedValue, setStoredValue] = React.useState(() => {
if (!storageAvailable) {
return initialValue;
}
try {
const item = storage === 'local' ?
window.localStorage.getItem(key) :
window.sessionStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// If error also return initialValue
return initialValue;
}
});

const setValue = (value) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
if (storageAvailable) {
const serializedValue = JSON.stringify(valueToStore);
storage === 'local' ?
window.localStorage.setItem(key, serializedValue) :
window.sessionStorage.setItem(key, serializedValue);
}
} catch (error) {
throw new Error(`PrimeReact useStorage: Failed to serialize the value at key: ${key}`);
}
};

return [storedValue, setValue];
}
/* eslint-enable */

0 comments on commit 24d64e5

Please sign in to comment.