import { useSuspenseQuery } from '@tanstack/react-query' import { noop } from 'lodash' import { useCallback } from 'react' import { StorageAdapter } from '../utils/native_adapters' const cacheKeyGenerator = (key: string) => [`StorageResource:${key}`] type SetValue = (_itemValue?: TCacheData | null) => Promise /** * Hook for using a storage adapter with React Query caching. * Similar to useAsyncStorage but accepts a StorageAdapter instead of using AsyncStorage directly. */ export function useStorage( storage: StorageAdapter, key: string, initialValue: TCacheData, throwOnError: boolean = false ): [TCacheData, SetValue] { const cacheKey = cacheKeyGenerator(key) const { data: value, refetch } = useSuspenseQuery({ queryKey: cacheKey, queryFn: () => storage .getItem(key) .then(storedValue => { if (!storedValue) return initialValue try { return JSON.parse(storedValue) as TCacheData } catch { return storedValue as TCacheData } }) .catch(e => { if (!throwOnError) return initialValue return Promise.reject(e) }), }) const setValue: SetValue = useCallback( itemValue => { if (itemValue === null || itemValue === undefined) { return storage .removeItem(key) .then(() => { refetch() }) .catch(noop) } return storage .setItem(key, JSON.stringify(itemValue)) .then(() => { refetch() }) .catch(e => { if (!throwOnError) return return Promise.reject(e) }) }, [throwOnError, key, refetch, storage] ) return [value || initialValue, setValue] }