Precache basic profile from posts for instant future navigations (#2795)

* skeleton for caching

* modify some existing logic

* refactor uri resolution query

* add precache feed posts

* adjustments

* remove prefetch on hover (maybe revert, just example)

* fix

* change arg name to match what we want

* optional infinite stale time

* use `ProfileViewDetailed`

* Revert "remove prefetch on hover (maybe revert, just example)"

This reverts commit 08609deb0defa7cea040438bc37dd3488ddc56f4.

* add warning comment back for stale time

* remove comment

* store profile with both the handle and did for query key

* remove extra block from revert

* clarify argument name

* remove QT cache

* structure queries the same (put `enabled` at bottom)

* use both `ProfileViewDetailed` and `ProfileView` for the query return type

* placeholder profile header

* remove logs

* remove a few other things we don't need

* add placeholder

* refactor

* refactor

* we don't need this height adjustment now

* use gray banner while loading

* set background color of image to the loading placeholder color

* reorg imports

* add border to header on loading

* Fix style

* Rm radius

* oops

* Undo edit

* Back out type changes

* Tighten some types and moderate shadow

* Move precaching fns to profile where the cache is

* Rename functions to match what they do now

* Remove anys

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
This commit is contained in:
Hailey 2024-02-08 17:38:16 -08:00 committed by GitHub
parent d9b62955b5
commit de28626001
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 170 additions and 85 deletions

View file

@ -1,9 +1,9 @@
import {QueryClient, useQuery, UseQueryResult} from '@tanstack/react-query'
import {AtUri, AppBskyActorDefs, AppBskyFeedDefs} from '@atproto/api'
import {useQuery, useQueryClient, UseQueryResult} from '@tanstack/react-query'
import {AtUri, AppBskyActorDefs} from '@atproto/api'
import {profileBasicQueryKey as RQKEY_PROFILE_BASIC} from './profile'
import {getAgent} from '#/state/session'
import {STALE} from '#/state/queries'
import {ThreadNode} from './post-thread'
export const RQKEY = (didOrHandle: string) => ['resolved-did', didOrHandle]
@ -22,55 +22,29 @@ export function useResolveUriQuery(uri: string | undefined): UriUseQueryResult {
}
export function useResolveDidQuery(didOrHandle: string | undefined) {
const queryClient = useQueryClient()
return useQuery<string, Error>({
staleTime: STALE.HOURS.ONE,
queryKey: RQKEY(didOrHandle || ''),
async queryFn() {
if (!didOrHandle) {
return ''
}
if (!didOrHandle.startsWith('did:')) {
const res = await getAgent().resolveHandle({handle: didOrHandle})
didOrHandle = res.data.did
}
return didOrHandle
queryKey: RQKEY(didOrHandle ?? ''),
queryFn: async () => {
if (!didOrHandle) return ''
// Just return the did if it's already one
if (didOrHandle.startsWith('did:')) return didOrHandle
const res = await getAgent().resolveHandle({handle: didOrHandle})
return res.data.did
},
initialData: () => {
// Return undefined if no did or handle
if (!didOrHandle) return
const profile =
queryClient.getQueryData<AppBskyActorDefs.ProfileViewBasic>(
RQKEY_PROFILE_BASIC(didOrHandle),
)
return profile?.did
},
enabled: !!didOrHandle,
})
}
export function precacheProfile(
queryClient: QueryClient,
profile:
| AppBskyActorDefs.ProfileView
| AppBskyActorDefs.ProfileViewBasic
| AppBskyActorDefs.ProfileViewDetailed,
) {
queryClient.setQueryData(RQKEY(profile.handle), profile.did)
}
export function precacheFeedPosts(
queryClient: QueryClient,
posts: AppBskyFeedDefs.FeedViewPost[],
) {
for (const post of posts) {
precacheProfile(queryClient, post.post.author)
}
}
export function precacheThreadPosts(
queryClient: QueryClient,
node: ThreadNode,
) {
if (node.type === 'post') {
precacheProfile(queryClient, node.post.author)
if (node.parent) {
precacheThreadPosts(queryClient, node.parent)
}
if (node.replies?.length) {
for (const reply of node.replies) {
precacheThreadPosts(queryClient, reply)
}
}
}
}