diff --git a/examples/SampleApp/yarn.lock b/examples/SampleApp/yarn.lock index a04aa0c0de..229ecb7b19 100644 --- a/examples/SampleApp/yarn.lock +++ b/examples/SampleApp/yarn.lock @@ -6634,6 +6634,11 @@ lodash-es@4.17.21: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash-es@4.17.23: + version "4.17.23" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.23.tgz#58c4360fd1b5d33afc6c0bbd3d1149349b1138e0" + integrity sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg== + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" diff --git a/examples/TypeScriptMessaging/App.tsx b/examples/TypeScriptMessaging/App.tsx index 4eeb980f14..49399cb22b 100644 --- a/examples/TypeScriptMessaging/App.tsx +++ b/examples/TypeScriptMessaging/App.tsx @@ -37,7 +37,6 @@ const options = { presence: true, state: true, watch: true, - limit: 30, }; I18nManager.forceRTL(false); diff --git a/package/package.json b/package/package.json index 494709b406..81f708d8e9 100644 --- a/package/package.json +++ b/package/package.json @@ -80,7 +80,7 @@ "path": "0.12.7", "react-native-markdown-package": "1.8.2", "react-native-url-polyfill": "^2.0.0", - "stream-chat": "^9.27.2", + "stream-chat": "^9.33.0", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { diff --git a/package/src/components/Channel/Channel.tsx b/package/src/components/Channel/Channel.tsx index 723cd9b907..fad110cec0 100644 --- a/package/src/components/Channel/Channel.tsx +++ b/package/src/components/Channel/Channel.tsx @@ -1147,7 +1147,8 @@ const ChannelWithContext = (props: PropsWithChildren) = if (channelMessagesState?.messages) { await channel?.watch({ messages: { - limit: channelMessagesState.messages.length + 30, + // Do we want to reduce this to the default as well ? + limit: channelMessagesState.messages.length, }, }); channel.offlineMode = false; diff --git a/package/src/components/Channel/__tests__/useMessageListPagination.test.js b/package/src/components/Channel/__tests__/useMessageListPagination.test.js index a41501fa39..00f0c75b6f 100644 --- a/package/src/components/Channel/__tests__/useMessageListPagination.test.js +++ b/package/src/components/Channel/__tests__/useMessageListPagination.test.js @@ -161,8 +161,8 @@ describe('useMessageListPagination', () => { await waitFor(() => { expect(queryFn).toHaveBeenCalledWith({ - messages: { id_lt: messages[0].id, limit: 20 }, - watchers: { limit: 20 }, + messages: { id_lt: messages[0].id }, + watchers: {}, }); expect(result.current.state.hasMore).toBe(true); expect(result.current.state.messages.length).toBe(40); @@ -252,8 +252,8 @@ describe('useMessageListPagination', () => { await waitFor(() => { expect(queryFn).toHaveBeenCalledWith({ - messages: { id_gt: messages[messages.length - 1].id, limit: 10 }, - watchers: { limit: 10 }, + messages: { id_gt: messages[messages.length - 1].id }, + watchers: {}, }); expect(result.current.state.hasMore).toBe(true); expect(result.current.state.messages.length).toBe(40); diff --git a/package/src/components/Channel/hooks/useMessageListPagination.tsx b/package/src/components/Channel/hooks/useMessageListPagination.tsx index 4c6e454e20..46b9766654 100644 --- a/package/src/components/Channel/hooks/useMessageListPagination.tsx +++ b/package/src/components/Channel/hooks/useMessageListPagination.tsx @@ -74,7 +74,7 @@ export const useMessageListPagination = ({ channel }: { channel: Channel }) => { /** * This function loads more messages before the first message in current channel state. */ - const loadMore = useStableCallback(async (limit: number = 20) => { + const loadMore = useStableCallback(async (limit?: number) => { if (!channel.state.messagePagination.hasPrev) { return; } @@ -103,7 +103,7 @@ export const useMessageListPagination = ({ channel }: { channel: Channel }) => { /** * This function loads more messages after the most recent message in current channel state. */ - const loadMoreRecent = useStableCallback(async (limit: number = 10) => { + const loadMoreRecent = useStableCallback(async (limit?: number) => { if (!channel.state.messagePagination.hasNext) { return; } diff --git a/package/src/components/ChannelList/hooks/usePaginatedChannels.ts b/package/src/components/ChannelList/hooks/usePaginatedChannels.ts index 4fd5b1ffaf..27af07468f 100644 --- a/package/src/components/ChannelList/hooks/usePaginatedChannels.ts +++ b/package/src/components/ChannelList/hooks/usePaginatedChannels.ts @@ -13,8 +13,6 @@ import { useChatContext } from '../../../contexts/chatContext/ChatContext'; import { useStateStore } from '../../../hooks'; import { useIsMountedRef } from '../../../hooks/useIsMountedRef'; -import { MAX_QUERY_CHANNELS_LIMIT } from '../utils'; - type Parameters = { channelManager: ChannelManager; enableOfflineSupport: boolean; @@ -24,10 +22,6 @@ type Parameters = { sort: ChannelSort; }; -const DEFAULT_OPTIONS = { - message_limit: 10, -}; - const RETRY_INTERVAL_IN_MS = 5000; type QueryType = 'queryLocalDB' | 'reload' | 'refresh' | 'loadChannels'; @@ -46,7 +40,7 @@ export const usePaginatedChannels = ({ channelManager, enableOfflineSupport, filters = {}, - options = DEFAULT_OPTIONS, + options = {}, sort = {}, }: Parameters) => { const [staticChannelsActive, setStaticChannelsActive] = useState(false); @@ -99,7 +93,6 @@ export const usePaginatedChannels = ({ setActiveQueryType(queryType); const newOptions = { - limit: options?.limit ?? MAX_QUERY_CHANNELS_LIMIT, offset: 0, ...options, }; diff --git a/package/src/components/MessageList/MessageList.tsx b/package/src/components/MessageList/MessageList.tsx index 4e591ccb03..12e988946d 100644 --- a/package/src/components/MessageList/MessageList.tsx +++ b/package/src/components/MessageList/MessageList.tsx @@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { FlatListProps, FlatList as FlatListType, + LayoutChangeEvent, ScrollViewProps, StyleSheet, View, @@ -9,6 +10,7 @@ import { ViewToken, } from 'react-native'; +import debounce from 'lodash/debounce'; import type { Channel, Event, LocalMessage, MessageResponse } from 'stream-chat'; import { useMessageList } from './hooks/useMessageList'; @@ -327,8 +329,8 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => { const renderItem = useCallback( ({ item: message, index }: { item: LocalMessage; index: number }) => { - const previousMessage = processedMessageListRef.current[index + 1]; - const nextMessage = processedMessageListRef.current[index - 1]; + const previousMessage = processedMessageList[index + 1]; + const nextMessage = processedMessageList[index - 1]; return ( { /> ); }, - [processedMessageListRef], + [processedMessageList], ); const messageListLengthBeforeUpdate = useRef(0); @@ -1126,6 +1128,44 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => { [additionalFlatListProps?.contentContainerStyle, contentContainer], ); + const viewportHeightRef = useRef(undefined); + + /** + * This debounced callback makes sure that if the current number of messages do not + * fill our screen, we load more messages continuously until we cover enough ground. + */ + const debouncedPrefillMessages = useMemo( + () => + debounce( + (viewportHeight: number, contentHeight: number) => { + if (viewportHeight >= contentHeight) { + maybeCallOnEndReached(); + } + }, + 500, + { + leading: false, + trailing: true, + }, + ), + [maybeCallOnEndReached], + ); + + const onContentSizeChange = useStableCallback((width: number, height: number) => { + if (additionalFlatListProps?.onContentSizeChange) { + additionalFlatListProps.onContentSizeChange(width, height); + } + + debouncedPrefillMessages(viewportHeightRef.current ?? 0, height); + }); + + const onLayout = useStableCallback((event: LayoutChangeEvent) => { + if (additionalFlatListProps?.onLayout) { + additionalFlatListProps.onLayout(event); + } + viewportHeightRef.current = event.nativeEvent.layout.height; + }); + if (!FlatList) { return null; } @@ -1168,6 +1208,8 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => { */ maintainVisibleContentPosition={maintainVisibleContentPosition} maxToRenderPerBatch={30} + onContentSizeChange={onContentSizeChange} + onLayout={onLayout} onMomentumScrollEnd={onUserScrollEvent} onScroll={handleScroll} onScrollBeginDrag={onScrollBeginDrag} diff --git a/package/yarn.lock b/package/yarn.lock index 24a3abe7e2..99d93b8855 100644 --- a/package/yarn.lock +++ b/package/yarn.lock @@ -8335,10 +8335,10 @@ stdin-discarder@^0.2.2: resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.2.2.tgz#390037f44c4ae1a1ae535c5fe38dc3aba8d997be" integrity sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ== -stream-chat@^9.27.2: - version "9.27.2" - resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-9.27.2.tgz#5b41173e513f3606c47c93f391693b589e663968" - integrity sha512-OdALDzg8lO8CAdl8deydJ1+O4wJ7mM9dPLeCwDppq/OQ4aFIS9X38P+IdXPcOCsgSS97UoVUuxD2/excC5PEeg== +stream-chat@^9.33.0: + version "9.33.0" + resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-9.33.0.tgz#3da6582ade9a22a808abe7f443b08137705bf792" + integrity sha512-JdeR6Nq2QEKBIKZsW8wnGa04pTHCiWmdIOqvWUVJ4DtmLzJ9oBBeBnHvPx1Q+RKbvpZqfjwvYaCwKY5ZFq+FxQ== dependencies: "@types/jsonwebtoken" "^9.0.8" "@types/ws" "^8.5.14"