1import * as SecureStore from 'expo-secure-store'; 2import * as React from 'react'; 3import { Platform } from 'react-native'; 4 5type UseStateHook<T> = [[boolean, T | null], (value?: T | null) => void]; 6 7function useAsyncState<T>(initialValue?: [boolean, T | null]): UseStateHook<T> { 8 return React.useReducer( 9 (state: [boolean, T | null], action?: T | null) => [ 10 false, 11 action === undefined ? null : action, 12 ], 13 initialValue ?? [true, undefined] 14 ) as UseStateHook<T>; 15} 16 17export async function setStorageItemAsync(key: string, value: string | null) { 18 if (Platform.OS === 'web') { 19 if (value == null) { 20 localStorage.removeItem(key); 21 } else { 22 localStorage.setItem(key, value); 23 } 24 } else { 25 if (value == null) { 26 await SecureStore.deleteItemAsync(key); 27 } else { 28 await SecureStore.setItemAsync(key, value); 29 } 30 } 31} 32 33export function useStorageState(key: string): UseStateHook<string> { 34 // Public 35 const [state, setState] = useAsyncState<string>(); 36 37 // Get 38 React.useEffect(() => { 39 if (Platform.OS === 'web') { 40 if (typeof localStorage !== 'undefined') { 41 setState(localStorage.getItem(key)); 42 } 43 } else { 44 SecureStore.getItemAsync(key).then((value) => { 45 setState(value); 46 }); 47 } 48 }, [key]); 49 50 // Set 51 const setValue = React.useCallback( 52 (value: string | null) => { 53 setStorageItemAsync(key, value).then(() => { 54 setState(value); 55 }); 56 }, 57 [key] 58 ); 59 60 return [state, setValue]; 61} 62