Thread queryClient explicitly through (#3328)

* Pass queryClient explicitly to resetProfilePostsQueries

* Pass queryClient explicitly to updatePostShadow

* Pass queryClient explicitly to updateProfileShadow
zio/stable
dan 2024-04-03 23:33:46 +01:00 committed by GitHub
parent 73df7e53b3
commit fc1e30afd6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 133 additions and 109 deletions

View File

@ -1,13 +1,14 @@
import {useEffect, useState, useMemo} from 'react'
import EventEmitter from 'eventemitter3'
import {useEffect, useMemo, useState} from 'react'
import {AppBskyFeedDefs} from '@atproto/api'
import {QueryClient} from '@tanstack/react-query'
import EventEmitter from 'eventemitter3'
import {batchedUpdates} from '#/lib/batchedUpdates'
import {Shadow, castAsShadow} from './types'
import {findAllPostsInQueryData as findAllPostsInNotifsQueryData} from '../queries/notifications/feed'
import {findAllPostsInQueryData as findAllPostsInFeedQueryData} from '../queries/post-feed'
import {findAllPostsInQueryData as findAllPostsInThreadQueryData} from '../queries/post-thread'
import {findAllPostsInQueryData as findAllPostsInSearchQueryData} from '../queries/search-posts'
import {queryClient} from 'lib/react-query'
import {castAsShadow, Shadow} from './types'
export type {Shadow} from './types'
export interface PostShadow {
@ -93,8 +94,12 @@ function mergeShadow(
})
}
export function updatePostShadow(uri: string, value: Partial<PostShadow>) {
const cachedPosts = findPostsInCache(uri)
export function updatePostShadow(
queryClient: QueryClient,
uri: string,
value: Partial<PostShadow>,
) {
const cachedPosts = findPostsInCache(queryClient, uri)
for (let post of cachedPosts) {
shadows.set(post, {...shadows.get(post), ...value})
}
@ -104,6 +109,7 @@ export function updatePostShadow(uri: string, value: Partial<PostShadow>) {
}
function* findPostsInCache(
queryClient: QueryClient,
uri: string,
): Generator<AppBskyFeedDefs.PostView, void> {
for (let post of findAllPostsInFeedQueryData(queryClient, uri)) {

View File

@ -1,7 +1,10 @@
import {useEffect, useState, useMemo} from 'react'
import EventEmitter from 'eventemitter3'
import {useEffect, useMemo, useState} from 'react'
import {AppBskyActorDefs} from '@atproto/api'
import {QueryClient} from '@tanstack/react-query'
import EventEmitter from 'eventemitter3'
import {batchedUpdates} from '#/lib/batchedUpdates'
import {findAllProfilesInQueryData as findAllProfilesInActorSearchQueryData} from '../queries/actor-search'
import {findAllProfilesInQueryData as findAllProfilesInListMembersQueryData} from '../queries/list-members'
import {findAllProfilesInQueryData as findAllProfilesInMyBlockedAccountsQueryData} from '../queries/my-blocked-accounts'
import {findAllProfilesInQueryData as findAllProfilesInMyMutedAccountsQueryData} from '../queries/my-muted-accounts'
@ -11,9 +14,7 @@ import {findAllProfilesInQueryData as findAllProfilesInProfileQueryData} from '.
import {findAllProfilesInQueryData as findAllProfilesInProfileFollowersQueryData} from '../queries/profile-followers'
import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '../queries/profile-follows'
import {findAllProfilesInQueryData as findAllProfilesInSuggestedFollowsQueryData} from '../queries/suggested-follows'
import {findAllProfilesInQueryData as findAllProfilesInActorSearchQueryData} from '../queries/actor-search'
import {Shadow, castAsShadow} from './types'
import {queryClient} from 'lib/react-query'
import {castAsShadow, Shadow} from './types'
export type {Shadow} from './types'
export interface ProfileShadow {
@ -58,10 +59,11 @@ export function useProfileShadow<
}
export function updateProfileShadow(
queryClient: QueryClient,
did: string,
value: Partial<ProfileShadow>,
) {
const cachedProfiles = findProfilesInCache(did)
const cachedProfiles = findProfilesInCache(queryClient, did)
for (let post of cachedProfiles) {
shadows.set(post, {...shadows.get(post), ...value})
}
@ -90,6 +92,7 @@ function mergeShadow<TProfileView extends AppBskyActorDefs.ProfileView>(
}
function* findProfilesInCache(
queryClient: QueryClient,
did: string,
): Generator<AppBskyActorDefs.ProfileView, void> {
yield* findAllProfilesInListMembersQueryData(queryClient, did)

View File

@ -3,37 +3,37 @@ import {AppState} from 'react-native'
import {
AppBskyFeedDefs,
AppBskyFeedPost,
ModerationDecision,
AtUri,
ModerationDecision,
} from '@atproto/api'
import {
useInfiniteQuery,
InfiniteData,
QueryKey,
QueryClient,
QueryKey,
useInfiniteQuery,
useQueryClient,
} from '@tanstack/react-query'
import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
import {useFeedTuners} from '../preferences/feed-tuners'
import {FeedTuner, FeedTunerFn, NoopFeedTuner} from 'lib/api/feed-manip'
import {FeedAPI, ReasonFeedSource} from 'lib/api/feed/types'
import {FollowingFeedAPI} from 'lib/api/feed/following'
import {AuthorFeedAPI} from 'lib/api/feed/author'
import {LikesFeedAPI} from 'lib/api/feed/likes'
import {CustomFeedAPI} from 'lib/api/feed/custom'
import {ListFeedAPI} from 'lib/api/feed/list'
import {MergeFeedAPI} from 'lib/api/feed/merge'
import {HomeFeedAPI} from '#/lib/api/feed/home'
import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
import {logger} from '#/logger'
import {STALE} from '#/state/queries'
import {precacheFeedPostProfiles} from './profile'
import {getAgent} from '#/state/session'
import {DEFAULT_LOGGED_OUT_PREFERENCES} from '#/state/queries/preferences/const'
import {KnownError} from '#/view/com/posts/FeedErrorMessage'
import {embedViewRecordToPostView, getEmbeddedPost} from './util'
import {useModerationOpts} from './preferences'
import {queryClient} from 'lib/react-query'
import {getAgent} from '#/state/session'
import {AuthorFeedAPI} from 'lib/api/feed/author'
import {CustomFeedAPI} from 'lib/api/feed/custom'
import {FollowingFeedAPI} from 'lib/api/feed/following'
import {LikesFeedAPI} from 'lib/api/feed/likes'
import {ListFeedAPI} from 'lib/api/feed/list'
import {MergeFeedAPI} from 'lib/api/feed/merge'
import {FeedAPI, ReasonFeedSource} from 'lib/api/feed/types'
import {FeedTuner, FeedTunerFn, NoopFeedTuner} from 'lib/api/feed-manip'
import {BSKY_FEED_OWNER_DIDS} from 'lib/constants'
import {KnownError} from '#/view/com/posts/FeedErrorMessage'
import {useFeedTuners} from '../preferences/feed-tuners'
import {useModerationOpts} from './preferences'
import {precacheFeedPostProfiles} from './profile'
import {embedViewRecordToPostView, getEmbeddedPost} from './util'
type ActorDid = string
type AuthorFilter =
@ -458,7 +458,11 @@ function assertSomePostsPassModeration(feed: AppBskyFeedDefs.FeedViewPost[]) {
}
}
export function resetProfilePostsQueries(did: string, timeout = 0) {
export function resetProfilePostsQueries(
queryClient: QueryClient,
did: string,
timeout = 0,
) {
setTimeout(() => {
queryClient.resetQueries({
predicate: query =>

View File

@ -1,12 +1,13 @@
import {useCallback} from 'react'
import {AppBskyFeedDefs, AtUri} from '@atproto/api'
import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query'
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
import {track} from '#/lib/analytics/analytics'
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
import {logEvent, LogEvents} from '#/lib/statsig/statsig'
import {updatePostShadow} from '#/state/cache/post-shadow'
import {Shadow} from '#/state/cache/types'
import {getAgent} from '#/state/session'
import {updatePostShadow} from '#/state/cache/post-shadow'
import {track} from '#/lib/analytics/analytics'
import {logEvent, LogEvents} from '#/lib/statsig/statsig'
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
export const RQKEY = (postUri: string) => ['post', postUri]
@ -62,6 +63,7 @@ export function usePostLikeMutationQueue(
logContext: LogEvents['post:like']['logContext'] &
LogEvents['post:unlike']['logContext'],
) {
const queryClient = useQueryClient()
const postUri = post.uri
const postCid = post.cid
const initialLikeUri = post.viewer?.like
@ -89,7 +91,7 @@ export function usePostLikeMutationQueue(
},
onSuccess(finalLikeUri) {
// finalize
updatePostShadow(postUri, {
updatePostShadow(queryClient, postUri, {
likeUri: finalLikeUri,
})
},
@ -97,19 +99,19 @@ export function usePostLikeMutationQueue(
const queueLike = useCallback(() => {
// optimistically update
updatePostShadow(postUri, {
updatePostShadow(queryClient, postUri, {
likeUri: 'pending',
})
return queueToggle(true)
}, [postUri, queueToggle])
}, [queryClient, postUri, queueToggle])
const queueUnlike = useCallback(() => {
// optimistically update
updatePostShadow(postUri, {
updatePostShadow(queryClient, postUri, {
likeUri: undefined,
})
return queueToggle(false)
}, [postUri, queueToggle])
}, [queryClient, postUri, queueToggle])
return [queueLike, queueUnlike]
}
@ -149,6 +151,7 @@ export function usePostRepostMutationQueue(
logContext: LogEvents['post:repost']['logContext'] &
LogEvents['post:unrepost']['logContext'],
) {
const queryClient = useQueryClient()
const postUri = post.uri
const postCid = post.cid
const initialRepostUri = post.viewer?.repost
@ -176,7 +179,7 @@ export function usePostRepostMutationQueue(
},
onSuccess(finalRepostUri) {
// finalize
updatePostShadow(postUri, {
updatePostShadow(queryClient, postUri, {
repostUri: finalRepostUri,
})
},
@ -184,19 +187,19 @@ export function usePostRepostMutationQueue(
const queueRepost = useCallback(() => {
// optimistically update
updatePostShadow(postUri, {
updatePostShadow(queryClient, postUri, {
repostUri: 'pending',
})
return queueToggle(true)
}, [postUri, queueToggle])
}, [queryClient, postUri, queueToggle])
const queueUnrepost = useCallback(() => {
// optimistically update
updatePostShadow(postUri, {
updatePostShadow(queryClient, postUri, {
repostUri: undefined,
})
return queueToggle(false)
}, [postUri, queueToggle])
}, [queryClient, postUri, queueToggle])
return [queueRepost, queueUnrepost]
}
@ -234,12 +237,13 @@ function usePostUnrepostMutation(
}
export function usePostDeleteMutation() {
const queryClient = useQueryClient()
return useMutation<void, Error, {uri: string}>({
mutationFn: async ({uri}) => {
await getAgent().deletePost(uri)
},
onSuccess(data, variables) {
updatePostShadow(variables.uri, {isDeleted: true})
updatePostShadow(queryClient, variables.uri, {isDeleted: true})
track('Post:Delete')
},
})

View File

@ -1,32 +1,33 @@
import {useCallback} from 'react'
import {Image as RNImage} from 'react-native-image-crop-picker'
import {
AtUri,
AppBskyActorDefs,
AppBskyActorProfile,
AppBskyActorGetProfile,
AppBskyFeedDefs,
AppBskyActorProfile,
AppBskyEmbedRecord,
AppBskyEmbedRecordWithMedia,
AppBskyFeedDefs,
AtUri,
} from '@atproto/api'
import {
QueryClient,
useMutation,
useQuery,
useQueryClient,
useMutation,
QueryClient,
} from '@tanstack/react-query'
import {Image as RNImage} from 'react-native-image-crop-picker'
import {useSession, getAgent} from '../session'
import {updateProfileShadow} from '../cache/profile-shadow'
import {track} from '#/lib/analytics/analytics'
import {uploadBlob} from '#/lib/api'
import {until} from '#/lib/async/until'
import {Shadow} from '#/state/cache/types'
import {resetProfilePostsQueries} from '#/state/queries/post-feed'
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
import {RQKEY as RQKEY_MY_MUTED} from './my-muted-accounts'
import {RQKEY as RQKEY_MY_BLOCKED} from './my-blocked-accounts'
import {STALE} from '#/state/queries'
import {track} from '#/lib/analytics/analytics'
import {logEvent, LogEvents} from '#/lib/statsig/statsig'
import {Shadow} from '#/state/cache/types'
import {STALE} from '#/state/queries'
import {resetProfilePostsQueries} from '#/state/queries/post-feed'
import {updateProfileShadow} from '../cache/profile-shadow'
import {getAgent, useSession} from '../session'
import {RQKEY as RQKEY_MY_BLOCKED} from './my-blocked-accounts'
import {RQKEY as RQKEY_MY_MUTED} from './my-muted-accounts'
import {ThreadNode} from './post-thread'
export const RQKEY = (did: string) => ['profile', did]
@ -190,6 +191,7 @@ export function useProfileFollowMutationQueue(
logContext: LogEvents['profile:follow']['logContext'] &
LogEvents['profile:unfollow']['logContext'],
) {
const queryClient = useQueryClient()
const did = profile.did
const initialFollowingUri = profile.viewer?.following
const followMutation = useProfileFollowMutation(logContext)
@ -215,7 +217,7 @@ export function useProfileFollowMutationQueue(
},
onSuccess(finalFollowingUri) {
// finalize
updateProfileShadow(did, {
updateProfileShadow(queryClient, did, {
followingUri: finalFollowingUri,
})
},
@ -223,19 +225,19 @@ export function useProfileFollowMutationQueue(
const queueFollow = useCallback(() => {
// optimistically update
updateProfileShadow(did, {
updateProfileShadow(queryClient, did, {
followingUri: 'pending',
})
return queueToggle(true)
}, [did, queueToggle])
}, [queryClient, did, queueToggle])
const queueUnfollow = useCallback(() => {
// optimistically update
updateProfileShadow(did, {
updateProfileShadow(queryClient, did, {
followingUri: undefined,
})
return queueToggle(false)
}, [did, queueToggle])
}, [queryClient, did, queueToggle])
return [queueFollow, queueUnfollow]
}
@ -269,6 +271,7 @@ function useProfileUnfollowMutation(
export function useProfileMuteMutationQueue(
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
) {
const queryClient = useQueryClient()
const did = profile.did
const initialMuted = profile.viewer?.muted
const muteMutation = useProfileMuteMutation()
@ -291,25 +294,25 @@ export function useProfileMuteMutationQueue(
},
onSuccess(finalMuted) {
// finalize
updateProfileShadow(did, {muted: finalMuted})
updateProfileShadow(queryClient, did, {muted: finalMuted})
},
})
const queueMute = useCallback(() => {
// optimistically update
updateProfileShadow(did, {
updateProfileShadow(queryClient, did, {
muted: true,
})
return queueToggle(true)
}, [did, queueToggle])
}, [queryClient, did, queueToggle])
const queueUnmute = useCallback(() => {
// optimistically update
updateProfileShadow(did, {
updateProfileShadow(queryClient, did, {
muted: false,
})
return queueToggle(false)
}, [did, queueToggle])
}, [queryClient, did, queueToggle])
return [queueMute, queueUnmute]
}
@ -341,6 +344,7 @@ function useProfileUnmuteMutation() {
export function useProfileBlockMutationQueue(
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
) {
const queryClient = useQueryClient()
const did = profile.did
const initialBlockingUri = profile.viewer?.blocking
const blockMutation = useProfileBlockMutation()
@ -366,7 +370,7 @@ export function useProfileBlockMutationQueue(
},
onSuccess(finalBlockingUri) {
// finalize
updateProfileShadow(did, {
updateProfileShadow(queryClient, did, {
blockingUri: finalBlockingUri,
})
},
@ -374,19 +378,19 @@ export function useProfileBlockMutationQueue(
const queueBlock = useCallback(() => {
// optimistically update
updateProfileShadow(did, {
updateProfileShadow(queryClient, did, {
blockingUri: 'pending',
})
return queueToggle(true)
}, [did, queueToggle])
}, [queryClient, did, queueToggle])
const queueUnblock = useCallback(() => {
// optimistically update
updateProfileShadow(did, {
updateProfileShadow(queryClient, did, {
blockingUri: undefined,
})
return queueToggle(false)
}, [did, queueToggle])
}, [queryClient, did, queueToggle])
return [queueBlock, queueUnblock]
}
@ -406,13 +410,14 @@ function useProfileBlockMutation() {
},
onSuccess(_, {did}) {
queryClient.invalidateQueries({queryKey: RQKEY_MY_BLOCKED()})
resetProfilePostsQueries(did, 1000)
resetProfilePostsQueries(queryClient, did, 1000)
},
})
}
function useProfileUnblockMutation() {
const {currentAccount} = useSession()
const queryClient = useQueryClient()
return useMutation<void, Error, {did: string; blockUri: string}>({
mutationFn: async ({blockUri}) => {
if (!currentAccount) {
@ -425,7 +430,7 @@ function useProfileUnblockMutation() {
})
},
onSuccess(_, {did}) {
resetProfilePostsQueries(did, 1000)
resetProfilePostsQueries(queryClient, did, 1000)
},
})
}

View File

@ -1,6 +1,5 @@
import React, {useMemo} from 'react'
import {StyleSheet} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
import {
AppBskyActorDefs,
moderateProfile,
@ -9,36 +8,38 @@ import {
} from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {CenteredView} from '../com/util/Views'
import {ListRef} from '../com/util/List'
import {ScreenHider} from '#/components/moderation/ScreenHider'
import {ProfileLists} from '../com/lists/ProfileLists'
import {ProfileFeedgens} from '../com/feeds/ProfileFeedgens'
import {PagerWithHeader} from 'view/com/pager/PagerWithHeader'
import {ErrorScreen} from '../com/util/error/ErrorScreen'
import {FAB} from '../com/util/fab/FAB'
import {s, colors} from 'lib/styles'
import {useAnalytics} from 'lib/analytics/analytics'
import {ComposeIcon2} from 'lib/icons'
import {useSetTitle} from 'lib/hooks/useSetTitle'
import {combinedDisplayName} from 'lib/strings/display-names'
import {resetProfilePostsQueries} from '#/state/queries/post-feed'
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
import {useProfileQuery} from '#/state/queries/profile'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {useSession, getAgent} from '#/state/session'
import {useModerationOpts} from '#/state/queries/preferences'
import {useLabelerInfoQuery} from '#/state/queries/labeler'
import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell'
import {cleanError} from '#/lib/strings/errors'
import {useComposerControls} from '#/state/shell/composer'
import {listenSoftReset} from '#/state/events'
import {isInvalidHandle} from '#/lib/strings/handles'
import {useFocusEffect} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query'
import {cleanError} from '#/lib/strings/errors'
import {isInvalidHandle} from '#/lib/strings/handles'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {listenSoftReset} from '#/state/events'
import {useLabelerInfoQuery} from '#/state/queries/labeler'
import {resetProfilePostsQueries} from '#/state/queries/post-feed'
import {useModerationOpts} from '#/state/queries/preferences'
import {useProfileQuery} from '#/state/queries/profile'
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
import {getAgent, useSession} from '#/state/session'
import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell'
import {useComposerControls} from '#/state/shell/composer'
import {useAnalytics} from 'lib/analytics/analytics'
import {useSetTitle} from 'lib/hooks/useSetTitle'
import {ComposeIcon2} from 'lib/icons'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {combinedDisplayName} from 'lib/strings/display-names'
import {colors, s} from 'lib/styles'
import {PagerWithHeader} from 'view/com/pager/PagerWithHeader'
import {ProfileHeader, ProfileHeaderLoading} from '#/screens/Profile/Header'
import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed'
import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels'
import {ProfileHeader, ProfileHeaderLoading} from '#/screens/Profile/Header'
import {ScreenHider} from '#/components/moderation/ScreenHider'
import {ProfileFeedgens} from '../com/feeds/ProfileFeedgens'
import {ProfileLists} from '../com/lists/ProfileLists'
import {ErrorScreen} from '../com/util/error/ErrorScreen'
import {FAB} from '../com/util/fab/FAB'
import {ListRef} from '../com/util/List'
import {CenteredView} from '../com/util/Views'
interface SectionRef {
scrollToTop: () => void
@ -48,6 +49,7 @@ type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'>
export function ProfileScreen({route}: Props) {
const {_} = useLingui()
const {currentAccount} = useSession()
const queryClient = useQueryClient()
const name =
route.params.name === 'me' ? currentAccount?.did : route.params.name
const moderationOpts = useModerationOpts()
@ -78,9 +80,9 @@ export function ProfileScreen({route}: Props) {
// When we open the profile, we want to reset the posts query if we are blocked.
React.useEffect(() => {
if (resolvedDid && profile?.viewer?.blockedBy) {
resetProfilePostsQueries(resolvedDid)
resetProfilePostsQueries(queryClient, resolvedDid)
}
}, [profile?.viewer?.blockedBy, resolvedDid])
}, [queryClient, profile?.viewer?.blockedBy, resolvedDid])
// Most pushes will happen here, since we will have only placeholder data
if (isLoadingDid || isLoadingProfile) {