Remove `getProfile` calls when loading feed (#3881)

* remove unnecessary `getProfile()` calls from feed load

add comments

ensure only if first

simplify

nit

handle cases where the parent is removed

add a comment

remove unnecessary `getProfile()` calls from feed load

limit only to the first post in the returned items

move the logic out of the render and into the query

add the grandparent properly

update `FeedItem`

bump package

update `FeedItem`

update `post-feed` query

update `FeedSlice`

* nit

* simplify logic

* always pass `parentAuthor`

* oops!

* update `DebugMod`
zio/stable
Hailey 2024-05-23 11:35:49 -07:00 committed by GitHub
parent 6d647551cd
commit 70f190d44f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 78 additions and 56 deletions

View File

@ -1,6 +1,7 @@
import React, {useCallback, useEffect, useRef} from 'react' import React, {useCallback, useEffect, useRef} from 'react'
import {AppState} from 'react-native' import {AppState} from 'react-native'
import { import {
AppBskyActorDefs,
AppBskyFeedDefs, AppBskyFeedDefs,
AppBskyFeedPost, AppBskyFeedPost,
AtUri, AtUri,
@ -72,6 +73,7 @@ export interface FeedPostSliceItem {
reason?: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource reason?: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource
feedContext: string | undefined feedContext: string | undefined
moderation: ModerationDecision moderation: ModerationDecision
parentAuthor?: AppBskyActorDefs.ProfileViewBasic
} }
export interface FeedPostSlice { export interface FeedPostSlice {
@ -302,6 +304,10 @@ export function usePostFeedQuery(
AppBskyFeedPost.validateRecord(item.post.record) AppBskyFeedPost.validateRecord(item.post.record)
.success .success
) { ) {
const parentAuthor =
item.reply?.parent?.author ??
slice.items[i + 1]?.reply?.grandparentAuthor
return { return {
_reactKey: `${slice._reactKey}-${i}-${item.post.uri}`, _reactKey: `${slice._reactKey}-${i}-${item.post.uri}`,
uri: item.post.uri, uri: item.post.uri,
@ -313,6 +319,7 @@ export function usePostFeedQuery(
: item.reason, : item.reason,
feedContext: item.feedContext || slice.feedContext, feedContext: item.feedContext || slice.feedContext,
moderation: moderations[i], moderation: moderations[i],
parentAuthor,
} }
} }
return undefined return undefined

View File

@ -1,6 +1,7 @@
import React, {memo, useMemo, useState} from 'react' import React, {memo, useMemo, useState} from 'react'
import {StyleSheet, View} from 'react-native' import {StyleSheet, View} from 'react-native'
import { import {
AppBskyActorDefs,
AppBskyFeedDefs, AppBskyFeedDefs,
AppBskyFeedPost, AppBskyFeedPost,
AtUri, AtUri,
@ -40,7 +41,18 @@ import {PostEmbeds} from '../util/post-embeds'
import {PostMeta} from '../util/PostMeta' import {PostMeta} from '../util/PostMeta'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {PreviewableUserAvatar} from '../util/UserAvatar' import {PreviewableUserAvatar} from '../util/UserAvatar'
import {UserInfoText} from '../util/UserInfoText'
interface FeedItemProps {
record: AppBskyFeedPost.Record
reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined
moderation: ModerationDecision
parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
showReplyTo: boolean
isThreadChild?: boolean
isThreadLastChild?: boolean
isThreadParent?: boolean
feedContext: string | undefined
}
export function FeedItem({ export function FeedItem({
post, post,
@ -48,19 +60,12 @@ export function FeedItem({
reason, reason,
feedContext, feedContext,
moderation, moderation,
parentAuthor,
showReplyTo,
isThreadChild, isThreadChild,
isThreadLastChild, isThreadLastChild,
isThreadParent, isThreadParent,
}: { }: FeedItemProps & {post: AppBskyFeedDefs.PostView}): React.ReactNode {
post: AppBskyFeedDefs.PostView
record: AppBskyFeedPost.Record
reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined
feedContext: string | undefined
moderation: ModerationDecision
isThreadChild?: boolean
isThreadLastChild?: boolean
isThreadParent?: boolean
}) {
const postShadowed = usePostShadow(post) const postShadowed = usePostShadow(post)
const richText = useMemo( const richText = useMemo(
() => () =>
@ -83,6 +88,8 @@ export function FeedItem({
reason={reason} reason={reason}
feedContext={feedContext} feedContext={feedContext}
richText={richText} richText={richText}
parentAuthor={parentAuthor}
showReplyTo={showReplyTo}
moderation={moderation} moderation={moderation}
isThreadChild={isThreadChild} isThreadChild={isThreadChild}
isThreadLastChild={isThreadLastChild} isThreadLastChild={isThreadLastChild}
@ -100,19 +107,14 @@ let FeedItemInner = ({
feedContext, feedContext,
richText, richText,
moderation, moderation,
parentAuthor,
showReplyTo,
isThreadChild, isThreadChild,
isThreadLastChild, isThreadLastChild,
isThreadParent, isThreadParent,
}: { }: FeedItemProps & {
post: Shadow<AppBskyFeedDefs.PostView>
record: AppBskyFeedPost.Record
reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined
feedContext: string | undefined
richText: RichTextAPI richText: RichTextAPI
moderation: ModerationDecision post: Shadow<AppBskyFeedDefs.PostView>
isThreadChild?: boolean
isThreadLastChild?: boolean
isThreadParent?: boolean
}): React.ReactNode => { }): React.ReactNode => {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const {openComposer} = useComposerControls() const {openComposer} = useComposerControls()
@ -124,14 +126,6 @@ let FeedItemInner = ({
}, [post.uri, post.author]) }, [post.uri, post.author])
const {sendInteraction} = useFeedFeedbackContext() const {sendInteraction} = useFeedFeedbackContext()
const replyAuthorDid = useMemo(() => {
if (!record?.reply) {
return ''
}
const urip = new AtUri(record.reply.parent?.uri || record.reply.root.uri)
return urip.hostname
}, [record?.reply])
const onPressReply = React.useCallback(() => { const onPressReply = React.useCallback(() => {
sendInteraction({ sendInteraction({
item: post.uri, item: post.uri,
@ -318,34 +312,8 @@ let FeedItemInner = ({
postHref={href} postHref={href}
onOpenAuthor={onOpenAuthor} onOpenAuthor={onOpenAuthor}
/> />
{!isThreadChild && replyAuthorDid !== '' && ( {!isThreadChild && showReplyTo && parentAuthor && (
<View style={[s.flexRow, s.mb2, s.alignCenter]}> <ReplyToLabel profile={parentAuthor} />
<FontAwesomeIcon
icon="reply"
size={9}
style={[
{color: pal.colors.textLight} as FontAwesomeIconStyle,
s.mr5,
]}
/>
<Text
type="md"
style={[pal.textLight, s.mr2]}
lineHeight={1.2}
numberOfLines={1}>
<Trans context="description">
Reply to{' '}
<ProfileHoverCard inline did={replyAuthorDid}>
<UserInfoText
type="md"
did={replyAuthorDid}
attr="displayName"
style={[pal.textLight]}
/>
</ProfileHoverCard>
</Trans>
</Text>
</View>
)} )}
<LabelsOnMyPost post={post} /> <LabelsOnMyPost post={post} />
<PostContent <PostContent
@ -434,6 +402,43 @@ let PostContent = ({
} }
PostContent = memo(PostContent) PostContent = memo(PostContent)
function ReplyToLabel({profile}: {profile: AppBskyActorDefs.ProfileViewBasic}) {
const pal = usePalette('default')
return (
<View style={[s.flexRow, s.mb2, s.alignCenter]}>
<FontAwesomeIcon
icon="reply"
size={9}
style={[{color: pal.colors.textLight} as FontAwesomeIconStyle, s.mr5]}
/>
<Text
type="md"
style={[pal.textLight, s.mr2]}
lineHeight={1.2}
numberOfLines={1}>
<Trans context="description">
Reply to{' '}
<ProfileHoverCard inline did={profile.did}>
<TextLinkOnWebOnly
type="md"
style={pal.textLight}
lineHeight={1.2}
numberOfLines={1}
href={makeProfileLink(profile)}
text={
profile.displayName
? sanitizeDisplayName(profile.displayName)
: sanitizeHandle(profile.handle)
}
/>
</ProfileHoverCard>
</Trans>
</Text>
</View>
)
}
const styles = StyleSheet.create({ const styles = StyleSheet.create({
outer: { outer: {
borderTopWidth: 1, borderTopWidth: 1,

View File

@ -22,6 +22,8 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
record={slice.items[0].record} record={slice.items[0].record}
reason={slice.items[0].reason} reason={slice.items[0].reason}
feedContext={slice.items[0].feedContext} feedContext={slice.items[0].feedContext}
parentAuthor={slice.items[0].parentAuthor}
showReplyTo={true}
moderation={slice.items[0].moderation} moderation={slice.items[0].moderation}
isThreadParent={isThreadParentAt(slice.items, 0)} isThreadParent={isThreadParentAt(slice.items, 0)}
isThreadChild={isThreadChildAt(slice.items, 0)} isThreadChild={isThreadChildAt(slice.items, 0)}
@ -32,6 +34,8 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
record={slice.items[1].record} record={slice.items[1].record}
reason={slice.items[1].reason} reason={slice.items[1].reason}
feedContext={slice.items[1].feedContext} feedContext={slice.items[1].feedContext}
parentAuthor={slice.items[1].parentAuthor}
showReplyTo={false}
moderation={slice.items[1].moderation} moderation={slice.items[1].moderation}
isThreadParent={isThreadParentAt(slice.items, 1)} isThreadParent={isThreadParentAt(slice.items, 1)}
isThreadChild={isThreadChildAt(slice.items, 1)} isThreadChild={isThreadChildAt(slice.items, 1)}
@ -43,6 +47,8 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
record={slice.items[last].record} record={slice.items[last].record}
reason={slice.items[last].reason} reason={slice.items[last].reason}
feedContext={slice.items[last].feedContext} feedContext={slice.items[last].feedContext}
parentAuthor={slice.items[2].parentAuthor}
showReplyTo={false}
moderation={slice.items[last].moderation} moderation={slice.items[last].moderation}
isThreadParent={isThreadParentAt(slice.items, last)} isThreadParent={isThreadParentAt(slice.items, last)}
isThreadChild={isThreadChildAt(slice.items, last)} isThreadChild={isThreadChildAt(slice.items, last)}
@ -62,6 +68,8 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
reason={slice.items[i].reason} reason={slice.items[i].reason}
feedContext={slice.items[i].feedContext} feedContext={slice.items[i].feedContext}
moderation={slice.items[i].moderation} moderation={slice.items[i].moderation}
parentAuthor={slice.items[i].parentAuthor}
showReplyTo={i === 0}
isThreadParent={isThreadParentAt(slice.items, i)} isThreadParent={isThreadParentAt(slice.items, i)}
isThreadChild={isThreadChildAt(slice.items, i)} isThreadChild={isThreadChildAt(slice.items, i)}
isThreadLastChild={ isThreadLastChild={

View File

@ -803,6 +803,8 @@ function MockPostFeedItem({
post={post} post={post}
record={post.record as AppBskyFeedPost.Record} record={post.record as AppBskyFeedPost.Record}
moderation={moderation} moderation={moderation}
parentAuthor={undefined}
showReplyTo={false}
reason={undefined} reason={undefined}
feedContext={''} feedContext={''}
/> />