Minimize cache purge when sorting feed

This commit is contained in:
Sam Becker 2025-07-04 12:57:06 -05:00
parent b7cb6715b7
commit bf78f786a7
6 changed files with 37 additions and 26 deletions

View File

@ -14,13 +14,14 @@ import { INITIAL_UPLOAD_STATE, UploadState } from '@/admin/upload';
import { AdminData } from '@/admin/actions';
import { RecipeProps } from '@/recipe';
import { getCountsForCategoriesCachedAction } from '@/category/actions';
import { SWRKey } from '@/swr';
export type AppStateContextType = {
// CORE
previousPathname?: string
hasLoaded?: boolean
hasLoadedWithAnimations?: boolean
invalidateSwr?: () => void
invalidateSwr?: (key?: SWRKey, revalidate?: boolean) => void
nextPhotoAnimation?: AnimationConfig
setNextPhotoAnimation?: (animationConfig?: AnimationConfig) => void
getNextPhotoAnimationId?: () => string

View File

@ -36,9 +36,8 @@ import { getCountsForCategoriesCachedAction } from '@/category/actions';
import {
canKeyBePurged,
canKeyBePurgedAndRevalidated,
SWR_KEY_GET_ADMIN_DATA,
SWR_KEY_GET_AUTH,
SWR_KEY_GET_COUNTS_FOR_CATEGORIES,
SWR_KEYS,
SWRKey,
} from '@/swr';
export default function AppStateProvider({
@ -129,13 +128,19 @@ export default function AppStateProvider({
}, []);
const { mutate } = useSWRConfig();
const invalidateSwr = useCallback(() => {
mutate(canKeyBePurged, undefined, { revalidate: false });
mutate(canKeyBePurgedAndRevalidated, undefined, { revalidate: true });
const invalidateSwr = useCallback((key?: SWRKey, revalidate?: boolean) => {
if (key) {
// Mutate specific key
mutate((k: string) => k?.startsWith(key), undefined, { revalidate });
} else {
// Mutate all keys that can be purged
mutate(canKeyBePurged, undefined, { revalidate: false });
mutate(canKeyBePurgedAndRevalidated, undefined, { revalidate: true });
}
}, [mutate]);
const { data: categoriesWithCounts } = useSWR(
SWR_KEY_GET_COUNTS_FOR_CATEGORIES,
SWR_KEYS.GET_COUNTS_FOR_CATEGORIES,
getCountsForCategoriesCachedAction,
);
@ -143,7 +148,7 @@ export default function AppStateProvider({
data: auth,
error: authError,
isLoading: isCheckingAuth,
} = useSWR(SWR_KEY_GET_AUTH, getAuthAction);
} = useSWR(SWR_KEYS.GET_AUTH, getAuthAction);
useEffect(() => {
if (auth === null || authError) {
setUserEmail(undefined);
@ -161,7 +166,7 @@ export default function AppStateProvider({
mutate: refreshAdminData,
isLoading: isLoadingAdminData,
} = useSWR(
isUserSignedIn ? SWR_KEY_GET_ADMIN_DATA : null,
isUserSignedIn ? SWR_KEYS.GET_ADMIN_DATA : null,
getAdminDataAction,
);
const updateAdminData = useCallback(

View File

@ -63,7 +63,7 @@ export default function AppViewSwitcher({
useEffect(() => {
if (hasLoadedRef.current) {
// After initial load, invalidate cache every time sort changes
invalidateSwr?.();
invalidateSwr?.('INFINITE_PHOTO_SCROLL');
}
hasLoadedRef.current = true;
}, [invalidateSwr, sortBy]);

View File

@ -8,7 +8,7 @@ import PhotoMedium from '@/photo/PhotoMedium';
import Spinner from '../Spinner';
import clsx from 'clsx';
import { useAppText } from '@/i18n/state/client';
import { SWR_KEY_SHARED_HOVER } from '@/swr';
import { SWR_KEYS } from '@/swr';
const { width, height } = getDimensionsFromSize(300, 16 / 9);
@ -37,7 +37,7 @@ export default function EntityHover({
data: photos,
isLoading,
} = useSWR(
isHovering ? `${SWR_KEY_SHARED_HOVER}-${hoverKey}` : null,
isHovering ? `${SWR_KEYS.SHARED_HOVER}-${hoverKey}` : null,
getPhotos, {
revalidateIfStale: false,
revalidateOnFocus: false,

View File

@ -18,7 +18,7 @@ import { useAppState } from '@/app/AppState';
import useVisible from '@/utility/useVisible';
import { ADMIN_DB_OPTIMIZE_ENABLED } from '@/app/config';
import { SortBy } from './db/sort';
import { SWR_KEY_INFINITE_PHOTO_SCROLL } from '@/swr';
import { SWR_KEYS } from '@/swr';
const SIZE_KEY_SEPARATOR = '__';
const getSizeFromKey = (key: string) =>
@ -65,7 +65,8 @@ export default function InfinitePhotoScroll({
const keyGenerator = useCallback(
(size: number, prev: Photo[]) => prev && prev.length === 0
? null
: `${SWR_KEY_INFINITE_PHOTO_SCROLL}-${cacheKey}__${size}`
// eslint-disable-next-line max-len
: `${SWR_KEYS.INFINITE_PHOTO_SCROLL}-${cacheKey}${SIZE_KEY_SEPARATOR}${size}`
, [cacheKey]);
const fetcher = useCallback((

View File

@ -1,18 +1,22 @@
export const SWR_KEY_GET_AUTH = 'getAuth';
export const SWR_KEY_GET_ADMIN_DATA = 'getAdminData';
export const SWR_KEY_GET_COUNTS_FOR_CATEGORIES = 'getCountsForCategories';
export const SWR_KEY_SHARED_HOVER = 'sharedHover';
export const SWR_KEY_INFINITE_PHOTO_SCROLL = 'infinitePhotoScroll';
export const SWR_KEYS = {
GET_AUTH: 'GET_AUTH',
GET_ADMIN_DATA: 'GET_ADMIN_DATA',
GET_COUNTS_FOR_CATEGORIES: 'GET_COUNTS_FOR_CATEGORIES',
SHARED_HOVER: 'SHARED_HOVER',
INFINITE_PHOTO_SCROLL: 'INFINITE_PHOTO_SCROLL',
} as const;
const KEYS_THAT_CAN_BE_PURGED = [
SWR_KEY_SHARED_HOVER,
SWR_KEY_INFINITE_PHOTO_SCROLL,
];
SWR_KEYS.SHARED_HOVER,
SWR_KEYS.INFINITE_PHOTO_SCROLL,
] as const;
const KEYS_THAT_CAN_BE_PURGED_AND_REVALIDATED = [
SWR_KEY_GET_ADMIN_DATA,
SWR_KEY_GET_COUNTS_FOR_CATEGORIES,
];
SWR_KEYS.GET_ADMIN_DATA,
SWR_KEYS.GET_COUNTS_FOR_CATEGORIES,
] as const;
export type SWRKey = typeof SWR_KEYS[keyof typeof SWR_KEYS];
export const canKeyBePurged = (key: string) =>
KEYS_THAT_CAN_BE_PURGED.some(k => key.startsWith(k));