From 9e8f8efccb01525d91ccf49ca2fc58e3193b07a2 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Tue, 17 Feb 2026 23:42:32 +0100 Subject: [PATCH 1/6] feat: use server defaults for querying channels --- examples/SampleApp/yarn.lock | 5 +++++ examples/TypeScriptMessaging/App.tsx | 1 - package/src/components/Channel/Channel.tsx | 3 ++- .../Channel/__tests__/useMessageListPagination.test.js | 4 ++-- .../components/Channel/hooks/useMessageListPagination.tsx | 2 +- .../components/ChannelList/hooks/usePaginatedChannels.ts | 7 +------ package/src/components/MessageList/MessageList.tsx | 6 +++--- 7 files changed, 14 insertions(+), 14 deletions(-) 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/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..2c32eb634b 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, limit: 10 }, + watchers: { limit: 10 }, }); 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..df08fbd6b0 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 = 10) => { if (!channel.state.messagePagination.hasPrev) { return; } diff --git a/package/src/components/ChannelList/hooks/usePaginatedChannels.ts b/package/src/components/ChannelList/hooks/usePaginatedChannels.ts index 4fd5b1ffaf..2344c639c8 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,9 +22,7 @@ type Parameters = { sort: ChannelSort; }; -const DEFAULT_OPTIONS = { - message_limit: 10, -}; +const DEFAULT_OPTIONS = {}; const RETRY_INTERVAL_IN_MS = 5000; @@ -99,7 +95,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..b1eed8853a 100644 --- a/package/src/components/MessageList/MessageList.tsx +++ b/package/src/components/MessageList/MessageList.tsx @@ -327,8 +327,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); From 48e9fd8722ae5281097a47bea868b0f372c1822d Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Wed, 18 Feb 2026 13:54:55 +0100 Subject: [PATCH 2/6] fix: MessageList prefilling capability --- .../components/MessageList/MessageList.tsx | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/package/src/components/MessageList/MessageList.tsx b/package/src/components/MessageList/MessageList.tsx index b1eed8853a..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'; @@ -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} From 1c498658d4dcb97ae6ed05e67b2c87965b4245db Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Wed, 18 Feb 2026 14:34:18 +0100 Subject: [PATCH 3/6] chore: bump stream-chat-js --- package/package.json | 2 +- package/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) 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/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" From a3f96b243645d810a0953ed1252c0f2ff4a740f3 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Wed, 18 Feb 2026 14:38:03 +0100 Subject: [PATCH 4/6] fix: pr remarks --- .../src/components/Channel/hooks/useMessageListPagination.tsx | 4 ++-- .../src/components/ChannelList/hooks/usePaginatedChannels.ts | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/package/src/components/Channel/hooks/useMessageListPagination.tsx b/package/src/components/Channel/hooks/useMessageListPagination.tsx index df08fbd6b0..bd00fc67fe 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 = 10) => { + 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 2344c639c8..27af07468f 100644 --- a/package/src/components/ChannelList/hooks/usePaginatedChannels.ts +++ b/package/src/components/ChannelList/hooks/usePaginatedChannels.ts @@ -22,8 +22,6 @@ type Parameters = { sort: ChannelSort; }; -const DEFAULT_OPTIONS = {}; - const RETRY_INTERVAL_IN_MS = 5000; type QueryType = 'queryLocalDB' | 'reload' | 'refresh' | 'loadChannels'; @@ -42,7 +40,7 @@ export const usePaginatedChannels = ({ channelManager, enableOfflineSupport, filters = {}, - options = DEFAULT_OPTIONS, + options = {}, sort = {}, }: Parameters) => { const [staticChannelsActive, setStaticChannelsActive] = useState(false); From 04ef1e43161eaa726551aa0f5cfbbb3b73948310 Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Wed, 18 Feb 2026 14:45:20 +0100 Subject: [PATCH 5/6] fix: ts issues --- .../src/components/Channel/hooks/useMessageListPagination.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/src/components/Channel/hooks/useMessageListPagination.tsx b/package/src/components/Channel/hooks/useMessageListPagination.tsx index bd00fc67fe..46b9766654 100644 --- a/package/src/components/Channel/hooks/useMessageListPagination.tsx +++ b/package/src/components/Channel/hooks/useMessageListPagination.tsx @@ -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) => { + const loadMoreRecent = useStableCallback(async (limit?: number) => { if (!channel.state.messagePagination.hasNext) { return; } From 393eb61f5c8eec01c190c753ef0399f8f683377d Mon Sep 17 00:00:00 2001 From: Ivan Sekovanikj Date: Wed, 18 Feb 2026 15:11:44 +0100 Subject: [PATCH 6/6] fix: tests --- .../Channel/__tests__/useMessageListPagination.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package/src/components/Channel/__tests__/useMessageListPagination.test.js b/package/src/components/Channel/__tests__/useMessageListPagination.test.js index 2c32eb634b..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: 10 }, - watchers: { limit: 10 }, + 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);