Skip to content

Instantly share code, notes, and snippets.

@jcblw
Created March 23, 2023 15:52
Show Gist options
  • Save jcblw/9deca82fc596a7b340646f9d394fa6ad to your computer and use it in GitHub Desktop.
Save jcblw/9deca82fc596a7b340646f9d394fa6ad to your computer and use it in GitHub Desktop.
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