diff --git a/lib/selectors/chat-selectors.js b/lib/selectors/chat-selectors.js --- a/lib/selectors/chat-selectors.js +++ b/lib/selectors/chat-selectors.js @@ -79,7 +79,7 @@ ); } -type ChatThreadItemLoader = { +export type ChatThreadItemLoader = { +threadInfo: ThreadInfo, +lastUpdatedAtLeastTimeIncludingSidebars: number, +lastUpdatedAtMostTimeIncludingSidebars: number, @@ -185,15 +185,36 @@ return useChatThreadItems(filteredThreadInfos); } -const sortFunc = _orderBy('lastUpdatedTimeIncludingSidebars')('desc'); -function useChatThreadItems( +function useFlattenedChatListLoaders(): $ReadOnlyArray { + return useFilteredChatListLoaders(threadInChatList); +} + +function useFilteredChatListLoaders( + filterFunction: (threadInfo: ?(ThreadInfo | RawThreadInfo)) => boolean, +): $ReadOnlyArray { + const threadInfos = useSelector(threadInfoSelector); + const filteredThreadInfos = React.useMemo( + () => Object.values(threadInfos).filter(filterFunction), + [threadInfos, filterFunction], + ); + return useChatThreadItemLoaders(filteredThreadInfos); +} + +function useChatThreadItemLoaders( threadInfos: $ReadOnlyArray, -): $ReadOnlyArray { +): $ReadOnlyArray { const getChatThreadItemLoader = useGetChatThreadItemLoader(); - const chatThreadItemLoaders = React.useMemo( + return React.useMemo( () => threadInfos.map(getChatThreadItemLoader), [threadInfos, getChatThreadItemLoader], ); +} + +const sortFunc = _orderBy('lastUpdatedTimeIncludingSidebars')('desc'); +function useChatThreadItems( + threadInfos: $ReadOnlyArray, +): $ReadOnlyArray { + const chatThreadItemLoaders = useChatThreadItemLoaders(threadInfos); const initialChatThreadItems = React.useMemo( () => chatThreadItemLoaders.map(loader => loader.initialChatThreadItem), @@ -756,6 +777,7 @@ messageListData, useFlattenedChatListData, useFilteredChatListData, + useFlattenedChatListLoaders, useChatThreadItems, useMessageListData, }; diff --git a/native/chat/chat-thread-list.react.js b/native/chat/chat-thread-list.react.js --- a/native/chat/chat-thread-list.react.js +++ b/native/chat/chat-thread-list.react.js @@ -26,7 +26,7 @@ import { useThreadListSearch } from 'lib/hooks/thread-search-hooks.js'; import { type ChatThreadItem, - useFlattenedChatListData, + useFlattenedChatListLoaders, } from 'lib/selectors/chat-selectors.js'; import { createPendingThread, @@ -35,6 +35,7 @@ import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { threadTypes } from 'lib/types/thread-types-enum.js'; import type { UserInfo } from 'lib/types/user-types.js'; +import ChatThreadItemLoaderCache from 'lib/utils/chat-thread-item-loader-cache.js'; import { ChatThreadListItem } from './chat-thread-list-item.react.js'; import ChatThreadListSearch from './chat-thread-list-search.react.js'; @@ -82,8 +83,19 @@ }; export type SearchStatus = 'inactive' | 'activating' | 'active'; +const pageSize = 25; + function ChatThreadList(props: BaseProps): React.Node { - const boundChatListData = useFlattenedChatListData(); + const chatThreadItemLoaders = useFlattenedChatListLoaders(); + const chatThreadItemLoaderCache = React.useMemo( + () => new ChatThreadItemLoaderCache(chatThreadItemLoaders), + [chatThreadItemLoaders], + ); + + const [boundChatListData, setBoundChatListData] = React.useState< + $ReadOnlyArray, + >(() => chatThreadItemLoaderCache.getAllChatThreadItems()); + const loggedInUserInfo = useLoggedInUserInfo(); const styles = useStyles(unboundStyles); const indicatorStyle = useSelector(indicatorStyleSelector); @@ -102,11 +114,22 @@ ); const [openedSwipeableID, setOpenedSwipeableID] = React.useState(''); - const [numItemsToDisplay, setNumItemsToDisplay] = React.useState(25); + const [numItemsToDisplay, setNumItemsToDisplay] = + React.useState(pageSize); + + React.useEffect(() => { + void (async () => { + const results = + await chatThreadItemLoaderCache.loadMostRecentChatThreadItems( + numItemsToDisplay, + ); + setBoundChatListData(results); + })(); + }, [numItemsToDisplay, chatThreadItemLoaderCache]); const onChangeSearchText = React.useCallback((updatedSearchText: string) => { setSearchText(updatedSearchText); - setNumItemsToDisplay(25); + setNumItemsToDisplay(pageSize); }, []); const scrollPos = React.useRef(0); @@ -314,7 +337,7 @@ if (partialListData.length === listData.length) { return; } - setNumItemsToDisplay(prevNumItems => prevNumItems + 25); + setNumItemsToDisplay(prevNumItems => prevNumItems + pageSize); }, [listData.length, partialListData.length]); const floatingAction = React.useMemo(() => { @@ -417,7 +440,7 @@ React.useEffect(() => { const clearNavigationBlurListener = navigation.addListener('blur', () => { - setNumItemsToDisplay(25); + setNumItemsToDisplay(pageSize); }); return () => {