diff --git a/src/favorites/FavoritesProvider.tsx b/src/favorites/FavoritesProvider.tsx index 81c2946..9ac816d 100644 --- a/src/favorites/FavoritesProvider.tsx +++ b/src/favorites/FavoritesProvider.tsx @@ -23,6 +23,7 @@ type FavoriteStatus = "unknown" | "favorited" | "notFavorited"; type FavoritesContextValue = { favoriteIds: Set; pendingIds: Set; + mutationVersion: number; statusFor: (resourceId: string) => FavoriteStatus; ensureFavoriteIds: (resourceIds: string[]) => Promise; toggleFavorite: (resourceId: string) => Promise; @@ -45,6 +46,7 @@ export function FavoritesProvider({ children }: { children: ReactNode }) { const [favoriteIds, setFavoriteIds] = useState>(() => new Set()); const [knownIds, setKnownIds] = useState>(() => new Set()); const [pendingIds, setPendingIds] = useState>(() => new Set()); + const [mutationVersion, setMutationVersion] = useState(0); const pendingAfterLoginRef = useRef(null); const lastAddressRef = useRef(null); const knownIdsRef = useRef>(new Set()); @@ -170,6 +172,7 @@ export function FavoritesProvider({ children }: { children: ReactNode }) { showToast( currentlyFavorite ? t("favoriteRemoved") : t("favoriteAdded"), ); + setMutationVersion((value) => value + 1); return nextFavorited; } catch (error) { markFavorite(resourceId, currentlyFavorite); @@ -221,6 +224,7 @@ export function FavoritesProvider({ children }: { children: ReactNode }) { () => ({ favoriteIds, pendingIds, + mutationVersion, statusFor, ensureFavoriteIds, toggleFavorite, @@ -230,6 +234,7 @@ export function FavoritesProvider({ children }: { children: ReactNode }) { ensureFavoriteIds, favoriteIds, markFavorite, + mutationVersion, pendingIds, statusFor, toggleFavorite, diff --git a/src/pages/Favorites/index.tsx b/src/pages/Favorites/index.tsx index 1514f7c..386ac8f 100644 --- a/src/pages/Favorites/index.tsx +++ b/src/pages/Favorites/index.tsx @@ -12,6 +12,17 @@ import { useWallet } from "../../wallet/WalletProvider"; const pageSize = 50; +type FavoritePosts = Awaited>["items"]; + +type FavoriteListCache = { + address: string; + lang: Lang; + mutationVersion: number; + posts: FavoritePosts; +}; + +let favoriteListCache: FavoriteListCache | null = null; + function useCategories(lang: Lang): Category[] { const [categories, setCategories] = useState(() => { const cached = readJSONCache( @@ -43,11 +54,9 @@ function useCategories(lang: Lang): Category[] { export default function Favorites() { const { lang, t } = useI18n(); const wallet = useWallet(); - const { markFavorite } = useFavorites(); + const { markFavorite, mutationVersion } = useFavorites(); const categories = useCategories(lang); - const [posts, setPosts] = useState< - Awaited>["items"] - >([]); + const [posts, setPosts] = useState([]); const [loading, setLoading] = useState(false); const [loaded, setLoaded] = useState(false); const [error, setError] = useState(""); @@ -56,7 +65,7 @@ export default function Favorites() { useSetPageTitle(t("favorites")); useEffect(() => { - if (!wallet.token || wallet.status !== "loggedIn") { + if (!wallet.token || wallet.status !== "loggedIn" || !wallet.address) { setPosts([]); setLoading(false); setLoaded(false); @@ -64,18 +73,40 @@ export default function Favorites() { return; } + const walletAddress = wallet.address; + const walletToken = wallet.token; + + if ( + reloadKey === 0 && + favoriteListCache?.address === walletAddress && + favoriteListCache.lang === lang && + favoriteListCache.mutationVersion === mutationVersion + ) { + setPosts(favoriteListCache.posts); + setLoading(false); + setLoaded(true); + setError(""); + return; + } + let cancelled = false; setLoading(true); setLoaded(false); setError(""); - listFavorites(wallet.token, { + listFavorites(walletToken, { limit: pageSize, includeUnavailable: true, }) .then((data) => { if (cancelled) return; const items = itemsOrEmpty(data.items); + favoriteListCache = { + address: walletAddress, + lang, + mutationVersion, + posts: items, + }; setPosts(items); items.forEach((post) => markFavorite(post.id, true)); setLoaded(true); @@ -97,7 +128,7 @@ export default function Favorites() { return () => { cancelled = true; }; - }, [markFavorite, reloadKey, t, wallet]); + }, [lang, markFavorite, mutationVersion, reloadKey, t, wallet]); if (wallet.status === "loading") { return (