diff --git a/src/components/ProfileHoverCard/index.web.tsx b/src/components/ProfileHoverCard/index.web.tsx index bda2380ece..b3761f1f95 100644 --- a/src/components/ProfileHoverCard/index.web.tsx +++ b/src/components/ProfileHoverCard/index.web.tsx @@ -430,7 +430,7 @@ function Inner({ () => moderateProfile(profile, moderationOpts), [profile, moderationOpts], ) - const [descriptionRT] = useRichText(profile.description ?? '') + const descriptionRT = useRichText(profile.description ?? '') const profileShadow = useProfileShadow(profile) const {follow, unfollow} = useFollowMethods({ profile: profileShadow, diff --git a/src/components/hooks/useRichText.ts b/src/components/hooks/useRichText.ts index caf6febc04..84984cbe5b 100644 --- a/src/components/hooks/useRichText.ts +++ b/src/components/hooks/useRichText.ts @@ -1,34 +1,10 @@ -import React from 'react' +import {useMemo} from 'react' import {RichText as RichTextAPI} from '@atproto/api' -import {useAgent} from '#/state/session' - -export function useRichText(text: string): [RichTextAPI, boolean] { - const [prevText, setPrevText] = React.useState(text) - const [rawRT, setRawRT] = React.useState(() => new RichTextAPI({text})) - const [resolvedRT, setResolvedRT] = React.useState(null) - const agent = useAgent() - if (text !== prevText) { - setPrevText(text) - setRawRT(new RichTextAPI({text})) - setResolvedRT(null) - // This will queue an immediate re-render - } - React.useEffect(() => { - let ignore = false - async function resolveRTFacets() { - // new each time - const resolvedRT = new RichTextAPI({text}) - await resolvedRT.detectFacets(agent) - if (!ignore) { - setResolvedRT(resolvedRT) - } - } - resolveRTFacets() - return () => { - ignore = true - } - }, [text, agent]) - const isResolving = resolvedRT === null - return [resolvedRT ?? rawRT, isResolving] +export function useRichText(text: string): RichTextAPI { + return useMemo(() => { + const rt = new RichTextAPI({text}) + rt.detectFacetsWithoutResolution() + return rt + }, [text]) } diff --git a/src/screens/Profile/components/ProfileFeedHeader.tsx b/src/screens/Profile/components/ProfileFeedHeader.tsx index 3c64c47729..2ab41da170 100644 --- a/src/screens/Profile/components/ProfileFeedHeader.tsx +++ b/src/screens/Profile/components/ProfileFeedHeader.tsx @@ -394,7 +394,7 @@ function DialogInner({ const playHaptic = useHaptics() const control = Dialog.useDialogContext() const reportDialogControl = useReportDialogControl() - const [rt] = useRichText(info.description.text) + const rt = useRichText(info.description.text) const {mutateAsync: likeFeed, isPending: isLikePending} = useLikeMutation() const {mutateAsync: unlikeFeed, isPending: isUnlikePending} = useUnlikeMutation() diff --git a/src/screens/StarterPack/StarterPackLandingScreen.tsx b/src/screens/StarterPack/StarterPackLandingScreen.tsx index a16eaf3515..015260cfe6 100644 --- a/src/screens/StarterPack/StarterPackLandingScreen.tsx +++ b/src/screens/StarterPack/StarterPackLandingScreen.tsx @@ -125,7 +125,7 @@ function LandingScreenLoaded({ const setActiveStarterPack = useSetActiveStarterPack() const {isTabletOrDesktop} = useWebMediaQueries() const androidDialogControl = useDialogControl() - const [descriptionRt] = useRichText(record.description || '') + const descriptionRt = useRichText(record.description || '') const [appClipOverlayVisible, setAppClipOverlayVisible] = React.useState(false) diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index dd1450c1c8..b79a8588f7 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -5,7 +5,6 @@ import { type AppBskyActorDefs, moderateProfile, type ModerationOpts, - RichText as RichTextAPI, } from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -32,7 +31,7 @@ import {useLabelerInfoQuery} from '#/state/queries/labeler' import {resetProfilePostsQueries} from '#/state/queries/post-feed' import {useProfileQuery} from '#/state/queries/profile' import {useResolveDidQuery} from '#/state/queries/resolve-uri' -import {useAgent, useSession} from '#/state/session' +import {useSession} from '#/state/session' import {useSetMinimalShellMode} from '#/state/shell' import {ProfileFeedgens} from '#/view/com/feeds/ProfileFeedgens' import {ProfileLists} from '#/view/com/lists/ProfileLists' @@ -44,6 +43,7 @@ import {ProfileHeader, ProfileHeaderLoading} from '#/screens/Profile/Header' import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed' import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels' import {atoms as a} from '#/alf' +import {useRichText} from '#/components/hooks/useRichText' import {Circle_And_Square_Stroke1_Corner0_Rounded_Filled as CircleAndSquareIcon} from '#/components/icons/CircleAndSquare' import {Heart2_Stroke1_Corner0_Rounded as HeartIcon} from '#/components/icons/Heart2' import {Image_Stroke1_Corner0_Rounded as ImageIcon} from '#/components/icons/Image' @@ -205,8 +205,8 @@ function ProfileScreenLoaded({ const description = profile.description ?? '' const hasDescription = description !== '' - const [descriptionRT, isResolvingDescriptionRT] = useRichText(description) - const showPlaceholder = isPlaceholderProfile || isResolvingDescriptionRT + const descriptionRT = useRichText(description) + const showPlaceholder = isPlaceholderProfile const moderation = useMemo( () => moderateProfile(profile, moderationOpts), [profile, moderationOpts], @@ -599,36 +599,6 @@ function ProfileScreenLoaded({ ) } -function useRichText(text: string): [RichTextAPI, boolean] { - const agent = useAgent() - const [prevText, setPrevText] = useState(text) - const [rawRT, setRawRT] = useState(() => new RichTextAPI({text})) - const [resolvedRT, setResolvedRT] = useState(null) - if (text !== prevText) { - setPrevText(text) - setRawRT(new RichTextAPI({text})) - setResolvedRT(null) - // This will queue an immediate re-render - } - useEffect(() => { - let ignore = false - async function resolveRTFacets() { - // new each time - const resolvedRT = new RichTextAPI({text}) - await resolvedRT.detectFacets(agent) - if (!ignore) { - setResolvedRT(resolvedRT) - } - } - void resolveRTFacets() - return () => { - ignore = true - } - }, [text, agent]) - const isResolving = resolvedRT === null - return [resolvedRT ?? rawRT, isResolving] -} - const styles = StyleSheet.create({ container: { flexDirection: 'column',