From 07df0c2c7953b85247a82a21db970eefcace9451 Mon Sep 17 00:00:00 2001 From: Ginger Date: Tue, 16 Sep 2025 09:23:06 -0400 Subject: [PATCH] Use Tanstack Query when fetching extended profiles to improve caching --- .../user-profile/UserRoomProfile.tsx | 4 +-- src/app/features/settings/account/Profile.tsx | 6 ++-- src/app/hooks/useExtendedProfile.ts | 30 +++++++++---------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/app/components/user-profile/UserRoomProfile.tsx b/src/app/components/user-profile/UserRoomProfile.tsx index ce985e94..6b9b24c6 100644 --- a/src/app/components/user-profile/UserRoomProfile.tsx +++ b/src/app/components/user-profile/UserRoomProfile.tsx @@ -23,7 +23,6 @@ import { CreatorChip } from './CreatorChip'; import { getDirectCreatePath, withSearchParam } from '../../pages/pathUtils'; import { DirectCreateSearchParams } from '../../pages/paths'; import { useExtendedProfile } from '../../hooks/useExtendedProfile'; -import { AsyncStatus } from '../../hooks/useAsyncCallback'; type UserRoomProfileProps = { userId: string; @@ -58,8 +57,7 @@ export function UserRoomProfile({ userId }: UserRoomProfileProps) { const displayName = getMemberDisplayName(room, userId); const avatarMxc = getMemberAvatarMxc(room, userId); const avatarUrl = (avatarMxc && mxcUrlToHttp(mx, avatarMxc, useAuthentication)) ?? undefined; - const [extendedProfileState, refreshExtendedProfile] = useExtendedProfile(userId); - const extendedProfile = extendedProfileState.status === AsyncStatus.Success ? extendedProfileState.data : undefined; + const [extendedProfile, refreshExtendedProfile] = useExtendedProfile(userId); const timezone = useMemo(() => { // @ts-expect-error Intl.supportedValuesOf isn't in the types yet const supportedTimezones = Intl.supportedValuesOf('timeZone') as string[]; diff --git a/src/app/features/settings/account/Profile.tsx b/src/app/features/settings/account/Profile.tsx index 2a542964..1c866102 100644 --- a/src/app/features/settings/account/Profile.tsx +++ b/src/app/features/settings/account/Profile.tsx @@ -519,9 +519,7 @@ export function Profile() { const userId = mx.getUserId() as string; const server = getMxIdServer(userId); - const [extendedProfileState, refreshExtendedProfile] = useExtendedProfile(userId); - const extendedProfile = - extendedProfileState.status === AsyncStatus.Success ? extendedProfileState.data : undefined; + const [extendedProfile, refreshExtendedProfile] = useExtendedProfile(userId); const [fieldDefaults, setFieldDefaults] = useState({}); useLayoutEffect(() => { @@ -559,7 +557,7 @@ export function Profile() { ); const saving = saveState.status === AsyncStatus.Loading; - const loadingExtendedProfile = extendedProfileState.status === AsyncStatus.Loading; + const loadingExtendedProfile = extendedProfile === undefined; const busy = saving || loadingExtendedProfile; return ( diff --git a/src/app/hooks/useExtendedProfile.ts b/src/app/hooks/useExtendedProfile.ts index 22e11acb..00a8c1be 100644 --- a/src/app/hooks/useExtendedProfile.ts +++ b/src/app/hooks/useExtendedProfile.ts @@ -1,6 +1,6 @@ -import { useCallback, useEffect } from 'react'; +import { useCallback } from 'react'; import z from 'zod'; -import { AsyncCallback, AsyncState, useAsyncCallback } from './useAsyncCallback'; +import { useQuery } from '@tanstack/react-query'; import { useMatrixClient } from './useMatrixClient'; import { useSpecVersions } from './useSpecVersions'; import { useCapabilities } from './useCapabilities'; @@ -30,26 +30,26 @@ export function useExtendedProfileSupported(): boolean { export function useExtendedProfile( userId: string -): [ - AsyncState, - AsyncCallback<[], ExtendedProfile | undefined> -] { +): [ExtendedProfile | undefined, () => Promise] { const mx = useMatrixClient(); const extendedProfileSupported = useExtendedProfileSupported(); - const [extendedProfileData, refresh] = useAsyncCallback( - useCallback(async () => { + const { data, refetch } = useQuery({ + queryKey: ['extended-profile', userId], + queryFn: useCallback(async () => { if (extendedProfileSupported) { return extendedProfile.parse(await mx.getExtendedProfile(userId)); } return undefined; - }, [mx, userId, extendedProfileSupported]) - ); + }, [mx, userId, extendedProfileSupported]), + refetchOnMount: false, + }); - useEffect(() => { - refresh(); - }, [refresh]); - - return [extendedProfileData, refresh]; + return [ + data, + async () => { + await refetch(); + }, + ]; } const LEGACY_FIELDS = ['displayname', 'avatar_url'];