import * as SecureStore from 'expo-secure-store'; import * as React from 'react'; import { Platform } from 'react-native'; type UseStateHook = [ [ boolean, T | null ], (value: T | null) => void ]; function useAsyncState( initialValue: [ boolean, T | null ] = [ true, null ], ): UseStateHook { return React.useReducer( (state: [ boolean, T | null ], action: T | null = null): [ boolean, T | null ] => [ false, action ], initialValue ) as UseStateHook; } export async function setStorageItemAsync(key: string, value: string | null) { if (Platform.OS === 'web') { try { if (value === null) { localStorage.removeItem( key ); } else { localStorage.setItem( key, value ); } } catch (e) { console.error( 'Local storage is unavailable:', e ); } } else { if (value == null) { await SecureStore.deleteItemAsync( key ); } else { await SecureStore.setItemAsync( key, value ); } } } export function useStorageState(key: string): UseStateHook { // Public const [ state, setState ] = useAsyncState(); // Get React.useEffect( () => { if (Platform.OS === 'web') { try { if (typeof localStorage !== 'undefined') { setState( localStorage.getItem( key ) ); } } catch (e) { console.error( 'Local storage is unavailable:', e ); } } else { SecureStore.getItemAsync( key ).then( (value: string | null) => { setState( value ); } ); } }, [ key ] ); // Set const setValue = React.useCallback( (value: string | null) => { setState( value ); setStorageItemAsync( key, value ); }, [ key ] ); return [ state, setValue ]; }