Repository navigation
refactor(MessageList): render thread messages from the thread unread snapshot - #3324
Conversation
β¦snapshot useMessageListElements read the unread snapshot from channel.messagePaginator even inside a thread, while the rest of MessageList reads it from the rendered list via useMessagePaginator(). A thread list re-rendered on every change to the channel snapshot, and a custom renderMessages received the channel state.
|
No actionable comments were generated in the recent review. π βΉοΈ Recent review info
π Walkthrough
Merge Risk: βͺ Minimal Β· up to
|
|
Size Change: +20 B (0%) Total Size: 884 kB π¦ View Changed
βΉοΈ View Unchanged
|
|
I would commit it as a fix |
Codecov Reportβ
All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3324 +/- ##
==========================================
+ Coverage 86.58% 86.63% +0.05%
==========================================
Files 546 546
Lines 16214 16215 +1
Branches 5087 5087
==========================================
+ Hits 14039 14048 +9
+ Misses 2175 2167 -8 β View full report in Codecov by Harness. π New features to boost your workflow:
|
## [15.0.0-rc.2](v15.0.0-rc.1...v15.0.0-rc.2) (2026-10-19) ### β BREAKING CHANGES * the `options` prop of `useCreateChatClient` is renamed to `config`, and its type changes from `StreamChatOptions` to the `stream-chat` configuration tree (`DeepPartial<InstanceConfigTree>`). Options that were passed at the top level now go under the `client` key, for example `options={{ baseURL, axiosRequestConfig }}` becomes `config={{ client: { baseURL, axiosRequestConfig } }}`. Requires a * requires stream-chat 10.0.0-rc.20 or later; client.activeChannels, client.getChannelById() and client.getChannelByMembers() are gone, use client.channelManager.get(cid), values() and client.channel() / client.channelManager.ensure({ type, id, data }); the thread list is client.threads.paginator, and threads come from client.threads.ensure() / get(). * getChannel() is removed; get the channel from client.channelManager.ensure() and call channel.ensureWatched(options). * channel search results, and the channels message search fetches for its results, are no longer watched; a custom search result component watches the channel when it is opened (channel.ensureWatched(), or jumpToMessage(id, { watchChannel: true }) for a message). ### Bug Fixes * **Attachment:** render giphy attachments in their own group with uniβ¦ ([#3322](#3322)) ([08b8c0e](08b8c0e)), closes [#2934](#2934) * **Attachment:** render giphy attachments in their own group with unique keys ([8967e37](8967e37)) * **MessageList:** restore the older-page anchor on iOS WebKit ([#3316](#3316)) ([e3247e1](e3247e1)) * **Poll:** port the poll vote debounce removal ([#3308](#3308)) to v15 ([#3309](#3309)) ([1af035e](1af035e)), closes [#1904](#1904) * **store:** provide getServerSnapshot to useStateStore so server rendering works ([0ccf60d](0ccf60d)) * **VirtualizedMessageList:** keep the last message fully visible in short lists ([#3318](#3318)) ([ef5c384](ef5c384)) ### Features * **ai-components:** add stream-chat-react/ai-components entry point ([50fe88e](50fe88e)) * **ai-components:** port the ai-components entry point ([#3314](#3314)) to v15 ([#3315](#3315)) ([9d1eacb](9d1eacb)) * pass the stream-chat configuration tree through useCreateChatClient ([#3321](#3321)) ([557ffcb](557ffcb)), closes [GetStream/stream-chat-js#1911](GetStream/stream-chat-js#1911) * replace StreamChat.activeChannels with entity item index for loaded channels ([#3310](#3310)) ([a41eed5](a41eed5)) ### Refactors * **MessageList:** render thread messages from the thread unread snapshot ([#3324](#3324)) ([ec6ce33](ec6ce33))
|
π This PR is included in version 15.0.0-rc.2 π The release is available on: Your semantic-release bot π¦π |
π― Goal
Inside a thread,
MessageListreads its unread state from the thread's message paginator (useMessagePaginator()): the unread banner, the "N new" notification anduseMarkReadall use the thread'sunreadStateSnapshot.useMessageListElementswas the exception. It always subscribed tochannel.messagePaginator.unreadStateSnapshot, even when the list rendered a thread.As a result:
renderMessageson every change to the channel's unread snapshot (e.g. a new channel message arriving while the channel is scrolled up), although nothing in the thread changed;renderMessagesused in a thread received the channel's unread state inchannelUnreadUiStateinstead of the thread's.No unread separator rendered incorrectly:
getIsFirstUnreadMessagealready returnsfalsefor thread replies (they carry aparent_id), so the default UI looked the same either way.π Implementation details
useMessageListElementsnow subscribes touseMessagePaginator().unreadStateSnapshot, which resolves to the thread's paginator inside a thread and the channel's otherwise. This matches howMessageList,useUnreadMessagesNotificationanduseMarkReadalready resolve it. Outside a thread nothing changes.Behavior note for integrators: a custom
renderMessagesrendered inside a thread now receives the thread's unread snapshot inchannelUnreadUiState. The parameter name is unchanged.Test added in
MessageList.test.tsx, using a real thread fromclient.threads.ensure()(the existing thread stub shares the channel's paginator, so it could not tell the two apart):renderMessages;It fails without the change and passes with it. The MessageList, Thread and Threads suites pass, and
yarn lint/yarn typesare clean.π¨ UI Changes
None. The change affects which store the thread's message list subscribes to, not what it renders.
Summary by CodeRabbit