diff --git a/lib/components/chat-mention-provider.react.js b/lib/components/chat-mention-provider.react.js --- a/lib/components/chat-mention-provider.react.js +++ b/lib/components/chat-mention-provider.react.js @@ -176,13 +176,22 @@ }; } +// Without allAtOnce, useChatMentionCandidatesObjAndUtils is very expensive. +// useResolvedThreadInfosObj would trigger its recalculation for each ENS name +// as it streams in, but we would prefer to trigger its recaculation just once +// for every update of the underlying Redux data. +const useResolvedThreadInfosObjOptions = { allAtOnce: true }; + function useChatMentionCandidatesObjAndUtils(): { chatMentionCandidatesObj: ChatMentionCandidatesObj, resolvedThreadInfos: ChatMentionCandidates, communityThreadIDForGenesisThreads: { +[id: string]: string }, } { const threadInfos = useSelector(threadInfoSelector); - const resolvedThreadInfos = useResolvedThreadInfosObj(threadInfos); + const resolvedThreadInfos = useResolvedThreadInfosObj( + threadInfos, + useResolvedThreadInfosObjOptions, + ); const { chatMentionCandidatesObj, communityThreadIDForGenesisThreads } = React.useMemo( () => getChatMentionCandidates(resolvedThreadInfos), diff --git a/lib/utils/entity-helpers.js b/lib/utils/entity-helpers.js --- a/lib/utils/entity-helpers.js +++ b/lib/utils/entity-helpers.js @@ -8,17 +8,19 @@ useENSNamesForEntityText, entityTextToRawString, } from './entity-text.js'; +import type { UseENSNamesOptions } from '../hooks/ens-cache.js'; import type { ThreadInfo, ResolvedThreadInfo } from '../types/thread-types.js'; import { values } from '../utils/objects.js'; function useResolvedThreadInfos( threadInfos: $ReadOnlyArray, + options?: ?UseENSNamesOptions, ): $ReadOnlyArray { const entityText = React.useMemo( () => threadInfos.map(threadInfo => threadInfo.uiName), [threadInfos], ); - const withENSNames = useENSNamesForEntityText(entityText); + const withENSNames = useENSNamesForEntityText(entityText, options); invariant( withENSNames, 'useENSNamesForEntityText only returns falsey when passed falsey', @@ -76,14 +78,18 @@ }, [threadInfos, withENSNames]); } -function useResolvedThreadInfosObj(threadInfosObj: { - +[id: string]: ThreadInfo, -}): { +[id: string]: ResolvedThreadInfo } { +function useResolvedThreadInfosObj( + threadInfosObj: { +[id: string]: ThreadInfo }, + options?: ?UseENSNamesOptions, +): { +[id: string]: ResolvedThreadInfo } { const threadInfosArray = React.useMemo( () => values(threadInfosObj), [threadInfosObj], ); - const resolvedThreadInfosArray = useResolvedThreadInfos(threadInfosArray); + const resolvedThreadInfosArray = useResolvedThreadInfos( + threadInfosArray, + options, + ); return React.useMemo(() => { const obj = {}; for (const resolvedThreadInfo of resolvedThreadInfosArray) { diff --git a/lib/utils/entity-text.js b/lib/utils/entity-text.js --- a/lib/utils/entity-text.js +++ b/lib/utils/entity-text.js @@ -6,7 +6,7 @@ import type { GetENSNames } from './ens-helpers.js'; import { tID, tShape, tString } from './validation-utils.js'; -import { useENSNames } from '../hooks/ens-cache.js'; +import { useENSNames, type UseENSNamesOptions } from '../hooks/ens-cache.js'; import { threadNoun } from '../shared/thread-utils.js'; import { stringForUser } from '../shared/user-utils.js'; import { @@ -533,12 +533,15 @@ .filter(Boolean); } -function useENSNamesForEntityText(entityText: ?EntityText): ?EntityText { +function useENSNamesForEntityText( + entityText: ?EntityText, + options?: ?UseENSNamesOptions, +): ?EntityText { const allObjects = React.useMemo( () => (entityText ? entityTextToObjects(entityText) : []), [entityText], ); - const objectsWithENSNames = useENSNames(allObjects); + const objectsWithENSNames = useENSNames(allObjects, options); return React.useMemo( () => entityText ? entityTextFromObjects(objectsWithENSNames) : entityText,