From 4c4ba553bdc4029e78eaf2ccf0f9df12e41a1b01 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 21 Nov 2023 22:42:30 +0000 Subject: [PATCH] Shadow refactoring and improvements (#1959) * Make shadow a type-only concept * Prevent unnecessary init state recalc * Use derived state instead of effects * Batch emitter updates * Use object first seen time instead of dataUpdatedAt * Stop threading dataUpdatedAt through * Use same value consistently --- src/lib/batchedUpdates.ts | 1 + src/lib/batchedUpdates.web.ts | 2 + src/state/cache/post-shadow.ts | 66 +++++++++-------- src/state/cache/profile-shadow.ts | 70 ++++++++++--------- src/state/cache/types.ts | 8 ++- .../auth/onboarding/RecommendedFollows.tsx | 4 +- .../onboarding/RecommendedFollowsItem.tsx | 4 +- src/view/com/lists/ListMembers.tsx | 3 - src/view/com/modals/ProfilePreview.tsx | 13 +--- src/view/com/notifications/Feed.tsx | 11 +-- src/view/com/notifications/FeedItem.tsx | 3 - src/view/com/post-thread/PostLikedBy.tsx | 18 ++--- src/view/com/post-thread/PostRepostedBy.tsx | 11 +-- src/view/com/post-thread/PostThread.tsx | 6 -- src/view/com/post-thread/PostThreadItem.tsx | 4 +- src/view/com/post/Post.tsx | 4 +- src/view/com/posts/Feed.tsx | 3 - src/view/com/posts/FeedItem.tsx | 4 +- src/view/com/posts/FeedSlice.tsx | 6 -- src/view/com/profile/ProfileCard.tsx | 7 +- src/view/com/profile/ProfileFollowers.tsx | 9 +-- src/view/com/profile/ProfileFollows.tsx | 9 +-- .../profile/ProfileHeaderSuggestedFollows.tsx | 12 +--- .../screens/ModerationBlockedAccounts.tsx | 2 - src/view/screens/ModerationMutedAccounts.tsx | 2 - src/view/screens/Profile.tsx | 6 +- src/view/screens/Search/Search.tsx | 30 ++------ 27 files changed, 115 insertions(+), 203 deletions(-) create mode 100644 src/lib/batchedUpdates.ts create mode 100644 src/lib/batchedUpdates.web.ts diff --git a/src/lib/batchedUpdates.ts b/src/lib/batchedUpdates.ts new file mode 100644 index 00000000..2530d6ca --- /dev/null +++ b/src/lib/batchedUpdates.ts @@ -0,0 +1 @@ +export {unstable_batchedUpdates as batchedUpdates} from 'react-native' diff --git a/src/lib/batchedUpdates.web.ts b/src/lib/batchedUpdates.web.ts new file mode 100644 index 00000000..03147ed6 --- /dev/null +++ b/src/lib/batchedUpdates.web.ts @@ -0,0 +1,2 @@ +// @ts-ignore +export {unstable_batchedUpdates as batchedUpdates} from 'react-dom' diff --git a/src/state/cache/post-shadow.ts b/src/state/cache/post-shadow.ts index d20f6eba..b21bb712 100644 --- a/src/state/cache/post-shadow.ts +++ b/src/state/cache/post-shadow.ts @@ -1,7 +1,8 @@ -import {useEffect, useState, useMemo, useCallback, useRef} from 'react' +import {useEffect, useState, useMemo, useCallback} from 'react' import EventEmitter from 'eventemitter3' import {AppBskyFeedDefs} from '@atproto/api' -import {Shadow} from './types' +import {batchedUpdates} from '#/lib/batchedUpdates' +import {Shadow, castAsShadow} from './types' export type {Shadow} from './types' const emitter = new EventEmitter() @@ -21,15 +22,36 @@ interface CacheEntry { value: PostShadow } +const firstSeenMap = new WeakMap() +function getFirstSeenTS(post: AppBskyFeedDefs.PostView): number { + let timeStamp = firstSeenMap.get(post) + if (timeStamp !== undefined) { + return timeStamp + } + timeStamp = Date.now() + firstSeenMap.set(post, timeStamp) + return timeStamp +} + export function usePostShadow( post: AppBskyFeedDefs.PostView, - ifAfterTS: number, ): Shadow | typeof POST_TOMBSTONE { - const [state, setState] = useState({ - ts: Date.now(), + const postSeenTS = getFirstSeenTS(post) + const [state, setState] = useState(() => ({ + ts: postSeenTS, value: fromPost(post), - }) - const firstRun = useRef(true) + })) + + const [prevPost, setPrevPost] = useState(post) + if (post !== prevPost) { + // if we got a new prop, assume it's fresher + // than whatever shadow state we accumulated + setPrevPost(post) + setState({ + ts: postSeenTS, + value: fromPost(post), + }) + } const onUpdate = useCallback( (value: Partial) => { @@ -46,30 +68,17 @@ export function usePostShadow( } }, [post.uri, onUpdate]) - // react to post updates - useEffect(() => { - // dont fire on first run to avoid needless re-renders - if (!firstRun.current) { - setState({ts: Date.now(), value: fromPost(post)}) - } - firstRun.current = false - }, [post]) - return useMemo(() => { - return state.ts > ifAfterTS + return state.ts > postSeenTS ? mergeShadow(post, state.value) - : {...post, isShadowed: true} - }, [post, state, ifAfterTS]) + : castAsShadow(post) + }, [post, state, postSeenTS]) } export function updatePostShadow(uri: string, value: Partial) { - emitter.emit(uri, value) -} - -export function isPostShadowed( - v: AppBskyFeedDefs.PostView | Shadow, -): v is Shadow { - return 'isShadowed' in v && !!v.isShadowed + batchedUpdates(() => { + emitter.emit(uri, value) + }) } function fromPost(post: AppBskyFeedDefs.PostView): PostShadow { @@ -89,7 +98,7 @@ function mergeShadow( if (shadow.isDeleted) { return POST_TOMBSTONE } - return { + return castAsShadow({ ...post, likeCount: shadow.likeCount, repostCount: shadow.repostCount, @@ -98,6 +107,5 @@ function mergeShadow( like: shadow.likeUri, repost: shadow.repostUri, }, - isShadowed: true, - } + }) } diff --git a/src/state/cache/profile-shadow.ts b/src/state/cache/profile-shadow.ts index 5323effa..6ebd3913 100644 --- a/src/state/cache/profile-shadow.ts +++ b/src/state/cache/profile-shadow.ts @@ -1,7 +1,8 @@ -import {useEffect, useState, useMemo, useCallback, useRef} from 'react' +import {useEffect, useState, useMemo, useCallback} from 'react' import EventEmitter from 'eventemitter3' import {AppBskyActorDefs} from '@atproto/api' -import {Shadow} from './types' +import {batchedUpdates} from '#/lib/batchedUpdates' +import {Shadow, castAsShadow} from './types' export type {Shadow} from './types' const emitter = new EventEmitter() @@ -22,15 +23,34 @@ type ProfileView = | AppBskyActorDefs.ProfileViewBasic | AppBskyActorDefs.ProfileViewDetailed -export function useProfileShadow( - profile: ProfileView, - ifAfterTS: number, -): Shadow { - const [state, setState] = useState({ - ts: Date.now(), +const firstSeenMap = new WeakMap() +function getFirstSeenTS(profile: ProfileView): number { + let timeStamp = firstSeenMap.get(profile) + if (timeStamp !== undefined) { + return timeStamp + } + timeStamp = Date.now() + firstSeenMap.set(profile, timeStamp) + return timeStamp +} + +export function useProfileShadow(profile: ProfileView): Shadow { + const profileSeenTS = getFirstSeenTS(profile) + const [state, setState] = useState(() => ({ + ts: profileSeenTS, value: fromProfile(profile), - }) - const firstRun = useRef(true) + })) + + const [prevProfile, setPrevProfile] = useState(profile) + if (profile !== prevProfile) { + // if we got a new prop, assume it's fresher + // than whatever shadow state we accumulated + setPrevProfile(profile) + setState({ + ts: profileSeenTS, + value: fromProfile(profile), + }) + } const onUpdate = useCallback( (value: Partial) => { @@ -47,33 +67,20 @@ export function useProfileShadow( } }, [profile.did, onUpdate]) - // react to profile updates - useEffect(() => { - // dont fire on first run to avoid needless re-renders - if (!firstRun.current) { - setState({ts: Date.now(), value: fromProfile(profile)}) - } - firstRun.current = false - }, [profile]) - return useMemo(() => { - return state.ts > ifAfterTS + return state.ts > profileSeenTS ? mergeShadow(profile, state.value) - : {...profile, isShadowed: true} - }, [profile, state, ifAfterTS]) + : castAsShadow(profile) + }, [profile, state, profileSeenTS]) } export function updateProfileShadow( uri: string, value: Partial, ) { - emitter.emit(uri, value) -} - -export function isProfileShadowed( - v: T | Shadow, -): v is Shadow { - return 'isShadowed' in v && !!v.isShadowed + batchedUpdates(() => { + emitter.emit(uri, value) + }) } function fromProfile(profile: ProfileView): ProfileShadow { @@ -88,7 +95,7 @@ function mergeShadow( profile: ProfileView, shadow: ProfileShadow, ): Shadow { - return { + return castAsShadow({ ...profile, viewer: { ...(profile.viewer || {}), @@ -96,6 +103,5 @@ function mergeShadow( muted: shadow.muted, blocking: shadow.blockingUri, }, - isShadowed: true, - } + }) } diff --git a/src/state/cache/types.ts b/src/state/cache/types.ts index 8bfcc867..055f4167 100644 --- a/src/state/cache/types.ts +++ b/src/state/cache/types.ts @@ -1 +1,7 @@ -export type Shadow = T & {isShadowed: true} +// This isn't a real property, but it prevents T being compatible with Shadow. +declare const shadowTag: unique symbol +export type Shadow = T & {[shadowTag]: true} + +export function castAsShadow(value: T): Shadow { + return value as any as Shadow +} diff --git a/src/view/com/auth/onboarding/RecommendedFollows.tsx b/src/view/com/auth/onboarding/RecommendedFollows.tsx index 7bf8c97e..372bbec6 100644 --- a/src/view/com/auth/onboarding/RecommendedFollows.tsx +++ b/src/view/com/auth/onboarding/RecommendedFollows.tsx @@ -24,7 +24,7 @@ export function RecommendedFollows({next}: Props) { const pal = usePalette('default') const {_} = useLingui() const {isTabletOrMobile} = useWebMediaQueries() - const {data: suggestedFollows, dataUpdatedAt} = useSuggestedFollowsQuery() + const {data: suggestedFollows} = useSuggestedFollowsQuery() const getSuggestedFollowsByActor = useGetSuggestedFollowersByActor() const [additionalSuggestions, setAdditionalSuggestions] = React.useState<{ [did: string]: AppBskyActorDefs.ProfileView[] @@ -162,7 +162,6 @@ export function RecommendedFollows({next}: Props) { renderItem={({item}) => ( @@ -197,7 +196,6 @@ export function RecommendedFollows({next}: Props) { renderItem={({item}) => ( diff --git a/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx b/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx index eadc3caf..93c515f3 100644 --- a/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx +++ b/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx @@ -18,7 +18,6 @@ import {logger} from '#/logger' type Props = { profile: AppBskyActorDefs.ProfileViewBasic - dataUpdatedAt: number moderation: ProfileModeration onFollowStateChange: (props: { did: string @@ -28,13 +27,12 @@ type Props = { export function RecommendedFollowsItem({ profile, - dataUpdatedAt, moderation, onFollowStateChange, }: React.PropsWithChildren) { const pal = usePalette('default') const {isMobile} = useWebMediaQueries() - const shadowedProfile = useProfileShadow(profile, dataUpdatedAt) + const shadowedProfile = useProfileShadow(profile) return ( @@ -198,7 +196,6 @@ export function ListMembers({ onPressTryAgain, onPressRetryLoadMore, isMobile, - dataUpdatedAt, ], ) diff --git a/src/view/com/modals/ProfilePreview.tsx b/src/view/com/modals/ProfilePreview.tsx index 8a505397..edfbf6a8 100644 --- a/src/view/com/modals/ProfilePreview.tsx +++ b/src/view/com/modals/ProfilePreview.tsx @@ -22,7 +22,6 @@ export function Component({did}: {did: string}) { const moderationOpts = useModerationOpts() const { data: profile, - dataUpdatedAt, error: profileError, refetch: refetchProfile, isFetching: isFetchingProfile, @@ -51,13 +50,7 @@ export function Component({did}: {did: string}) { ) } if (profile && moderationOpts) { - return ( - - ) + return } // should never happen return ( @@ -71,15 +64,13 @@ export function Component({did}: {did: string}) { function ComponentLoaded({ profile: profileUnshadowed, - dataUpdatedAt, moderationOpts, }: { profile: AppBskyActorDefs.ProfileViewDetailed - dataUpdatedAt: number moderationOpts: ModerationOpts }) { const pal = usePalette('default') - const profile = useProfileShadow(profileUnshadowed, dataUpdatedAt) + const profile = useProfileShadow(profileUnshadowed) const {screen} = useAnalytics() const moderation = React.useMemo( () => moderateProfile(profile, moderationOpts), diff --git a/src/view/com/notifications/Feed.tsx b/src/view/com/notifications/Feed.tsx index 2dac75e3..ba88f78c 100644 --- a/src/view/com/notifications/Feed.tsx +++ b/src/view/com/notifications/Feed.tsx @@ -38,7 +38,6 @@ export function Feed({ const {markAllRead} = useUnreadNotificationsApi() const { data, - dataUpdatedAt, isLoading, isFetching, isFetched, @@ -132,15 +131,9 @@ export function Feed({ } else if (item === LOADING_ITEM) { return } - return ( - - ) + return }, - [onPressRetryLoadMore, dataUpdatedAt, moderationOpts], + [onPressRetryLoadMore, moderationOpts], ) const showHeaderSpinner = !isPTRing && isFetching && !isLoading diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx index 75d44a2f..aaa2ea2c 100644 --- a/src/view/com/notifications/FeedItem.tsx +++ b/src/view/com/notifications/FeedItem.tsx @@ -58,11 +58,9 @@ interface Author { let FeedItem = ({ item, - dataUpdatedAt, moderationOpts, }: { item: FeedNotification - dataUpdatedAt: number moderationOpts: ModerationOpts }): React.ReactNode => { const pal = usePalette('default') @@ -135,7 +133,6 @@ let FeedItem = ({ accessible={false}> { - return ( - - ) - }, - [dataUpdatedAt], - ) + const renderItem = useCallback(({item}: {item: GetLikes.Like}) => { + return ( + + ) + }, []) if (isFetchingResolvedUri || !isFetched) { return ( diff --git a/src/view/com/post-thread/PostRepostedBy.tsx b/src/view/com/post-thread/PostRepostedBy.tsx index 67c043a2..1162fec4 100644 --- a/src/view/com/post-thread/PostRepostedBy.tsx +++ b/src/view/com/post-thread/PostRepostedBy.tsx @@ -20,7 +20,6 @@ export function PostRepostedBy({uri}: {uri: string}) { } = useResolveUriQuery(uri) const { data, - dataUpdatedAt, isFetching, isFetched, isFetchingNextPage, @@ -57,15 +56,9 @@ export function PostRepostedBy({uri}: {uri: string}) { const renderItem = useCallback( ({item}: {item: ActorDefs.ProfileViewBasic}) => { - return ( - - ) + return }, - [dataUpdatedAt], + [], ) if (isFetchingResolvedUri || !isFetched) { diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx index 1c9f2c16..55448fcc 100644 --- a/src/view/com/post-thread/PostThread.tsx +++ b/src/view/com/post-thread/PostThread.tsx @@ -73,7 +73,6 @@ export function PostThread({ refetch, isRefetching, data: thread, - dataUpdatedAt, } = usePostThreadQuery(uri) const {data: preferences} = usePreferencesQuery() const rootPost = thread?.type === 'post' ? thread.post : undefined @@ -111,7 +110,6 @@ export function PostThread({ void onPressReply: () => void @@ -295,7 +291,6 @@ function PostThreadLoaded({ void }) { const moderationOpts = useModerationOpts() - const postShadowed = usePostShadow(post, dataUpdatedAt) + const postShadowed = usePostShadow(post) const richText = useMemo( () => new RichTextAPI({ diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index 00dd4419..2e8019e7 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -30,12 +30,10 @@ import {Shadow, usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow' export function Post({ post, - dataUpdatedAt, showReplyLine, style, }: { post: AppBskyFeedDefs.PostView - dataUpdatedAt: number showReplyLine?: boolean style?: StyleProp }) { @@ -48,7 +46,7 @@ export function Post({ : undefined, [post], ) - const postShadowed = usePostShadow(post, dataUpdatedAt) + const postShadowed = usePostShadow(post) const richText = useMemo( () => record diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx index cd4560c1..fc6d7769 100644 --- a/src/view/com/posts/Feed.tsx +++ b/src/view/com/posts/Feed.tsx @@ -76,7 +76,6 @@ let Feed = ({ const opts = React.useMemo(() => ({enabled}), [enabled]) const { data, - dataUpdatedAt, isFetching, isFetched, isError, @@ -200,7 +199,6 @@ let Feed = ({ return ( @@ -208,7 +206,6 @@ let Feed = ({ }, [ feed, - dataUpdatedAt, error, onPressTryAgain, onPressRetryLoadMore, diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index 19f2b0e6..dfb0cfcf 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -40,7 +40,6 @@ export function FeedItem({ record, reason, moderation, - dataUpdatedAt, isThreadChild, isThreadLastChild, isThreadParent, @@ -49,12 +48,11 @@ export function FeedItem({ record: AppBskyFeedPost.Record reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined moderation: PostModeration - dataUpdatedAt: number isThreadChild?: boolean isThreadLastChild?: boolean isThreadParent?: boolean }) { - const postShadowed = usePostShadow(post, dataUpdatedAt) + const postShadowed = usePostShadow(post) const richText = useMemo( () => new RichTextAPI({ diff --git a/src/view/com/posts/FeedSlice.tsx b/src/view/com/posts/FeedSlice.tsx index 06f11aa6..a3bacdc1 100644 --- a/src/view/com/posts/FeedSlice.tsx +++ b/src/view/com/posts/FeedSlice.tsx @@ -11,12 +11,10 @@ import {makeProfileLink} from 'lib/routes/links' let FeedSlice = ({ slice, - dataUpdatedAt, ignoreFilterFor, moderationOpts, }: { slice: FeedPostSlice - dataUpdatedAt: number ignoreFilterFor?: string moderationOpts: ModerationOpts }): React.ReactNode => { @@ -44,7 +42,6 @@ let FeedSlice = ({ record={slice.items[0].record} reason={slice.items[0].reason} moderation={moderations[0]} - dataUpdatedAt={dataUpdatedAt} isThreadParent={isThreadParentAt(slice.items, 0)} isThreadChild={isThreadChildAt(slice.items, 0)} /> @@ -54,7 +51,6 @@ let FeedSlice = ({ record={slice.items[1].record} reason={slice.items[1].reason} moderation={moderations[1]} - dataUpdatedAt={dataUpdatedAt} isThreadParent={isThreadParentAt(slice.items, 1)} isThreadChild={isThreadChildAt(slice.items, 1)} /> @@ -65,7 +61,6 @@ let FeedSlice = ({ record={slice.items[last].record} reason={slice.items[last].reason} moderation={moderations[last]} - dataUpdatedAt={dataUpdatedAt} isThreadParent={isThreadParentAt(slice.items, last)} isThreadChild={isThreadChildAt(slice.items, last)} isThreadLastChild @@ -83,7 +78,6 @@ let FeedSlice = ({ record={slice.items[i].record} reason={slice.items[i].reason} moderation={moderations[i]} - dataUpdatedAt={dataUpdatedAt} isThreadParent={isThreadParentAt(slice.items, i)} isThreadChild={isThreadChildAt(slice.items, i)} isThreadLastChild={ diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx index cd985545..279e00d7 100644 --- a/src/view/com/profile/ProfileCard.tsx +++ b/src/view/com/profile/ProfileCard.tsx @@ -27,7 +27,6 @@ import {useSession} from '#/state/session' export function ProfileCard({ testID, profile: profileUnshadowed, - dataUpdatedAt, noBg, noBorder, followers, @@ -36,7 +35,6 @@ export function ProfileCard({ }: { testID?: string profile: AppBskyActorDefs.ProfileViewBasic - dataUpdatedAt: number noBg?: boolean noBorder?: boolean followers?: AppBskyActorDefs.ProfileView[] | undefined @@ -46,7 +44,7 @@ export function ProfileCard({ style?: StyleProp }) { const pal = usePalette('default') - const profile = useProfileShadow(profileUnshadowed, dataUpdatedAt) + const profile = useProfileShadow(profileUnshadowed) const moderationOpts = useModerationOpts() if (!moderationOpts) { return null @@ -202,13 +200,11 @@ export function ProfileCardWithFollowBtn({ noBg, noBorder, followers, - dataUpdatedAt, }: { profile: AppBskyActorDefs.ProfileViewBasic noBg?: boolean noBorder?: boolean followers?: AppBskyActorDefs.ProfileView[] | undefined - dataUpdatedAt: number }) { const {currentAccount} = useSession() const isMe = profile.did === currentAccount?.did @@ -224,7 +220,6 @@ export function ProfileCardWithFollowBtn({ ? undefined : profileShadow => } - dataUpdatedAt={dataUpdatedAt} /> ) } diff --git a/src/view/com/profile/ProfileFollowers.tsx b/src/view/com/profile/ProfileFollowers.tsx index b9e8c0c4..45c1b3ad 100644 --- a/src/view/com/profile/ProfileFollowers.tsx +++ b/src/view/com/profile/ProfileFollowers.tsx @@ -20,7 +20,6 @@ export function ProfileFollowers({name}: {name: string}) { } = useResolveDidQuery(name) const { data, - dataUpdatedAt, isFetching, isFetched, isFetchingNextPage, @@ -58,13 +57,9 @@ export function ProfileFollowers({name}: {name: string}) { const renderItem = React.useCallback( ({item}: {item: ActorDefs.ProfileViewBasic}) => ( - + ), - [dataUpdatedAt], + [], ) if (isFetchingDid || !isFetched) { diff --git a/src/view/com/profile/ProfileFollows.tsx b/src/view/com/profile/ProfileFollows.tsx index 77ae72da..e1dce78a 100644 --- a/src/view/com/profile/ProfileFollows.tsx +++ b/src/view/com/profile/ProfileFollows.tsx @@ -20,7 +20,6 @@ export function ProfileFollows({name}: {name: string}) { } = useResolveDidQuery(name) const { data, - dataUpdatedAt, isFetching, isFetched, isFetchingNextPage, @@ -58,13 +57,9 @@ export function ProfileFollows({name}: {name: string}) { const renderItem = React.useCallback( ({item}: {item: ActorDefs.ProfileViewBasic}) => ( - + ), - [dataUpdatedAt], + [], ) if (isFetchingDid || !isFetched) { diff --git a/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx b/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx index 6e060af4..f648c980 100644 --- a/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx +++ b/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx @@ -65,7 +65,7 @@ export function ProfileHeaderSuggestedFollows({ } }, [active, animatedHeight, track]) - const {isLoading, data, dataUpdatedAt} = useSuggestedFollowsByActorQuery({ + const {isLoading, data} = useSuggestedFollowsByActorQuery({ did: actorDid, }) @@ -127,11 +127,7 @@ export function ProfileHeaderSuggestedFollows({ ) : data ? ( data.suggestions.map(profile => ( - + )) ) : ( @@ -196,15 +192,13 @@ function SuggestedFollowSkeleton() { function SuggestedFollow({ profile: profileUnshadowed, - dataUpdatedAt, }: { profile: AppBskyActorDefs.ProfileView - dataUpdatedAt: number }) { const {track} = useAnalytics() const pal = usePalette('default') const moderationOpts = useModerationOpts() - const profile = useProfileShadow(profileUnshadowed, dataUpdatedAt) + const profile = useProfileShadow(profileUnshadowed) const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile) const onPressFollow = React.useCallback(async () => { diff --git a/src/view/screens/ModerationBlockedAccounts.tsx b/src/view/screens/ModerationBlockedAccounts.tsx index 1c592dde..c03275f5 100644 --- a/src/view/screens/ModerationBlockedAccounts.tsx +++ b/src/view/screens/ModerationBlockedAccounts.tsx @@ -40,7 +40,6 @@ export const ModerationBlockedAccounts = withAuthRequired( const [isPTRing, setIsPTRing] = React.useState(false) const { data, - dataUpdatedAt, isFetching, isError, error, @@ -95,7 +94,6 @@ export const ModerationBlockedAccounts = withAuthRequired( testID={`blockedAccount-${index}`} key={item.did} profile={item} - dataUpdatedAt={dataUpdatedAt} /> ) return ( diff --git a/src/view/screens/ModerationMutedAccounts.tsx b/src/view/screens/ModerationMutedAccounts.tsx index 36bcbf1f..c0ff17eb 100644 --- a/src/view/screens/ModerationMutedAccounts.tsx +++ b/src/view/screens/ModerationMutedAccounts.tsx @@ -40,7 +40,6 @@ export const ModerationMutedAccounts = withAuthRequired( const [isPTRing, setIsPTRing] = React.useState(false) const { data, - dataUpdatedAt, isFetching, isError, error, @@ -95,7 +94,6 @@ export const ModerationMutedAccounts = withAuthRequired( testID={`mutedAccount-${index}`} key={item.did} profile={item} - dataUpdatedAt={dataUpdatedAt} /> ) return ( diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index 5411bc04..7b25e012 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -57,7 +57,6 @@ export const ProfileScreen = withAuthRequired( } = useResolveDidQuery(name) const { data: profile, - dataUpdatedAt, error: profileError, refetch: refetchProfile, isFetching: isFetchingProfile, @@ -100,7 +99,6 @@ export const ProfileScreen = withAuthRequired( return ( @@ -125,16 +123,14 @@ export const ProfileScreen = withAuthRequired( function ProfileScreenLoaded({ profile: profileUnshadowed, - dataUpdatedAt, moderationOpts, hideBackButton, }: { profile: AppBskyActorDefs.ProfileViewDetailed - dataUpdatedAt: number moderationOpts: ModerationOpts hideBackButton: boolean }) { - const profile = useProfileShadow(profileUnshadowed, dataUpdatedAt) + const profile = useProfileShadow(profileUnshadowed) const {currentAccount} = useSession() const setMinimalShellMode = useSetMinimalShellMode() const {openComposer} = useComposerControls() diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx index 0788dd79..9cd7ee37 100644 --- a/src/view/screens/Search/Search.tsx +++ b/src/view/screens/Search/Search.tsx @@ -111,7 +111,6 @@ function EmptyState({message, error}: {message: string; error?: string}) { function SearchScreenSuggestedFollows() { const pal = usePalette('default') const {currentAccount} = useSession() - const [dataUpdatedAt, setDataUpdatedAt] = React.useState(0) const [suggestions, setSuggestions] = React.useState< AppBskyActorDefs.ProfileViewBasic[] >([]) @@ -141,7 +140,6 @@ function SearchScreenSuggestedFollows() { ) setSuggestions(Array.from(friendsOfFriends.values())) - setDataUpdatedAt(Date.now()) } try { @@ -151,23 +149,12 @@ function SearchScreenSuggestedFollows() { error: e, }) } - }, [ - currentAccount, - setSuggestions, - setDataUpdatedAt, - getSuggestedFollowsByActor, - ]) + }, [currentAccount, setSuggestions, getSuggestedFollowsByActor]) return suggestions.length ? ( ( - - )} + renderItem={({item}) => } keyExtractor={item => item.did} // @ts-ignore web only -prf desktopFixedHeight @@ -205,7 +192,6 @@ function SearchScreenPostResults({query}: {query: string}) { fetchNextPage, isFetchingNextPage, hasNextPage, - dataUpdatedAt, } = useSearchPostsQuery({query}) const onPullToRefresh = React.useCallback(async () => { @@ -258,7 +244,7 @@ function SearchScreenPostResults({query}: {query: string}) { data={items} renderItem={({item}) => { if (item.type === 'post') { - return + return } else { return } @@ -291,7 +277,6 @@ function SearchScreenPostResults({query}: {query: string}) { function SearchScreenUserResults({query}: {query: string}) { const {_} = useLingui() const [isFetched, setIsFetched] = React.useState(false) - const [dataUpdatedAt, setDataUpdatedAt] = React.useState(0) const [results, setResults] = React.useState< AppBskyActorDefs.ProfileViewBasic[] >([]) @@ -302,7 +287,6 @@ function SearchScreenUserResults({query}: {query: string}) { const searchResults = await search({query, limit: 30}) if (searchResults) { - setDataUpdatedAt(Date.now()) setResults(results) setIsFetched(true) } @@ -314,7 +298,7 @@ function SearchScreenUserResults({query}: {query: string}) { setResults([]) setIsFetched(false) } - }, [query, setDataUpdatedAt, search, results]) + }, [query, search, results]) return isFetched ? ( <> @@ -322,11 +306,7 @@ function SearchScreenUserResults({query}: {query: string}) { ( - + )} keyExtractor={item => item.did} // @ts-ignore web only -prf