Created
March 23, 2023 15:52
-
-
Save jcblw/9deca82fc596a7b340646f9d394fa6ad to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import AsyncStorage from "@react-native-async-storage/async-storage"; | |
import { useCallback, useEffect, useRef, useState } from "react"; | |
const safeParse = <T extends unknown>(value: string | null) => { | |
if (value === null) { | |
return null; | |
} | |
try { | |
return JSON.parse(value) as T; | |
} catch (error) { | |
return null; | |
} | |
}; | |
interface AsyncStorageValues { | |
["daily_community_quote_key"]: { storedAt: string; quoteKey: string }; | |
} | |
/** | |
* useStorage is a hook that interfaces with the AsyncStorage API, with a similar interface as | |
* react-query's useQuery hook. It is also typed by this global storage interface. The reason this is | |
* here and not use the async storage hook directly is because of the auto fetching on mount and state management. | |
* | |
* @param key The key to use for the AsyncStorage API | |
* @returns An object with the following properties: | |
* - item: The item stored in AsyncStorage, or null if it doesn't exist | |
* - error: An error if one occurred | |
* - isLoading: Whether the item is currently being fetched | |
* - getItem: A function that fetches the item from AsyncStorage | |
* - setItem: A function that sets the item in AsyncStorage | |
*/ | |
export const useStorage = <Key extends keyof AsyncStorageValues>(key: Key) => { | |
const [item, setLocalItem] = useState<AsyncStorageValues[Key] | null>(null); | |
const [error, setError] = useState<Error | null>(null); | |
const [isLoading, setIsLoading] = useState<boolean>(false); | |
const isMounted = useRef(true); | |
const getItem = useCallback(async () => { | |
try { | |
setIsLoading(true); | |
const value = safeParse( | |
await AsyncStorage.getItem(key) | |
) as AsyncStorageValues[Key]; | |
if (!isMounted.current) { | |
return; | |
} | |
setLocalItem(value); | |
setIsLoading(false); | |
} catch (error) { | |
if (!isMounted.current) { | |
return; | |
} | |
setError(error); | |
setIsLoading(false); | |
} | |
}, [key]); | |
const setItem = useCallback( | |
async (value: AsyncStorageValues[Key]) => { | |
setLocalItem(value); | |
try { | |
await AsyncStorage.setItem(key, JSON.stringify(value)); | |
} catch (error) { | |
if (!isMounted.current) { | |
return; | |
} | |
setError(error); | |
} | |
}, | |
[key] | |
); | |
useEffect(() => { | |
getItem(); | |
}, [getItem]); | |
useEffect( | |
() => () => { | |
isMounted.current = false; | |
}, | |
[] | |
); | |
return { item, error, isLoading, getItem, setItem }; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment