-
Notifications
You must be signed in to change notification settings - Fork 0
/
cookies.tsx
94 lines (86 loc) · 3.15 KB
/
cookies.tsx
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import React, { Context, ReactNode, useState, createContext, useMemo, useRef } from 'react';
import { useCookies, CookiesProvider } from 'react-cookie';
import Cookies, { Cookie, CookieSetOptions } from 'universal-cookie';
import Debug from 'debug';
import { IStoreContext, IUseStore, defaultContext, useStore } from './store';
const debug = Debug('store:cookie');
export const CookiesStoreContext = createContext(defaultContext);
export const CookiesStoreProvider = ({
context = CookiesStoreContext,
children,
defaultCookies,
options = {},
}: {
context?: Context<IStoreContext>;
children?: ReactNode;
defaultCookies?: Cookie;
options?: CookieSetOptions;
}) => {
const [cookies] = useState(() => defaultCookies && new Cookies(defaultCookies));
return <CookiesProvider cookies={cookies}>
<CookiesStoreProviderCore options={options} context={context} defaultCookies={defaultCookies}>
{children}
</CookiesStoreProviderCore>
</CookiesProvider>;
};
export const CookiesStoreProviderCore = ({
context = CookiesStoreContext,
children,
defaultCookies = {},
options = {},
}: {
context?: Context<IStoreContext>;
children?: ReactNode;
defaultCookies?: any;
options?: CookieSetOptions;
}) => {
const [useStore] = useState(() => {
return function useStore<T>(
key: string,
defaultValue: T,
): ReturnType<IUseStore<T>> {
const memoDefaultValue = useMemo(() => defaultValue, []);
const [cookie, setCookie, removeCookie] = useCookies([key]);
const stateRef = useRef<any>();
stateRef.current = cookie?.[key];
const [setValue] = useState(() => (value) => {
const _value = typeof(value) === 'function' ? value(stateRef.current) : value;
debug('setValue', { key, defaultValue: memoDefaultValue, value: _value, options });
return setCookie(key, { value: _value }, options);
});
const [unsetValue] = useState(() => () => {
debug('unsetValue', { key, defaultValue: memoDefaultValue, options });
return removeCookie(key, options);
});
let defaultCookie;
try {
defaultCookie = defaultCookies && defaultCookies[key] && typeof(defaultCookies[key]) === 'string' ? JSON.parse(defaultCookies[key]).value : defaultCookies[key];
} catch (error) {
debug('setStore:error', { error, key, defaultValue: memoDefaultValue, defaultCookie: defaultCookies[key] });
}
return [(cookie?.[key] && cookie?.[key]?.value) || (defaultCookies && defaultCookie) || memoDefaultValue, setValue, unsetValue, false];
};
});
return <context.Provider value={{ useStore }}>
{children}
</context.Provider>;
};
/**
* A hook to use a cookie store
*
* @example
* ```
* // Wrap your component with CookiesStoreProvider to use useCookiesStore hook.
* <CookiesStoreProvider>
* <MyComponent />
* </CookiesStoreProvider>
*
* function MyComponent() {
* const [value, setValue, unsetValue, isLoading] = useCookiesStore('key', 'defaultValue');
* return <div>{value}</div>;
* }
* ```
*/
export function useCookiesStore<T extends any>(key: string, defaultValue: T, context = CookiesStoreContext) {
return useStore(key, defaultValue, context);
}