-
Notifications
You must be signed in to change notification settings - Fork 0
/
use-session-storage.ts
58 lines (51 loc) · 1.81 KB
/
use-session-storage.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import { Dispatch, SetStateAction, useState } from 'react';
import { useIsomorphicLayoutEffect } from './use-isomorphic-layout-effect';
import { useUpdateEffect } from './use-update-effect';
import { identityFn } from './utils';
type Options<TData> = {
key: string;
initialValue?: TData | null;
fallbackValue?: TData | null;
storageToStateFn?: (
data: TData,
alternativeValue: { initialValue: TData | null; fallbackValue: TData | null },
) => TData | null;
};
/**
* Like `useState` but persisted on `sessionStorage`.
*
* SSG/SSR-friendly.
*
* •
*
* @param options Options.
* @param options.key sessionStorage key.
* @param options.initialValue Initial value of the state.
* @param options.fallbackValue Fallback value when error parsing the value or null. Default to null.
* @param options.storageToStateFn Function to determine how session storage data transformed to a state.
* Default to `(data) => data`. You can add validation here, example `(data) => isExpired ? null : data`
*/
export function useSessionStorage<TData>(
options: Options<TData>,
): [TData | null, Dispatch<SetStateAction<TData | null>>] {
const { key, initialValue = null, fallbackValue = null, storageToStateFn = identityFn } = options;
const [value, setValue] = useState<TData | null>(initialValue);
useIsomorphicLayoutEffect(() => {
const storageData = sessionStorage.getItem(key);
if (!storageData) {
setValue(fallbackValue);
return;
}
try {
const parsedValue = JSON.parse(storageData) as TData;
const nextValue = storageToStateFn(parsedValue, { initialValue, fallbackValue });
setValue(nextValue);
} catch {
setValue(fallbackValue);
}
}, []);
useUpdateEffect(() => {
sessionStorage.setItem(key, JSON.stringify(value));
}, [value]);
return [value, setValue];
}