Skip to content

fix: stability and perf fixes - #1910

Merged
isekovanic merged 12 commits into
release-v10from
fix/v10-stability-and-perf-fixes
Oct 13, 2026
Merged

isekovanic merged 12 commits into
release-v10from
fix/v10-stability-and-perf-fixes

Conversation

@isekovanic

Copy link
Copy Markdown
Contributor

CLA

  • I have signed the Stream CLA (required).
  • Code changes are tested

Description of the changes, What, Why and How?

Linear ticket: https://linear.app/stream/issue/REACT-1226/stability-and-performance-fixes

Fixes pagination, channel list ordering and offline cold start issues in the v10 state layer, each reproduced against the release candidate and confirmed on device.

  • 1be4ec66: Fixes an issue where jumping to a message could leave the message list loading forever. Jumps that commit their own state (the first-unread query, a failed jumpToMessage, jumpToTheLatestMessage from an older window) never cleared isLoading, so the list never paginated again. Also fixes jumps inside a thread: they were sent without a limit, and the replies endpoint ignores id_around without one and returns the newest replies, so tapping a quoted reply did nothing and the thread stopped paginating. Jumps now always send a limit, and their head/tail flags are measured against that limit.
  • bb9bd6ed: Fixes an issue where, after a jump, the list could decide there were no more messages above or below the target and stop paginating. The flags were guessed from the target's position in the page, which only matches how the server splits the page for odd limits (the default thread page size of 50 broke both directions). They are now derived from how many messages came back on each side.
  • bdd5acac: Fixes an issue where an empty page (asking for newer messages when the newest are already loaded) cleared the cursor for the other direction, so the list could no longer load older messages.
  • 3ca29362: Fixes an issue where a channel that was added while empty and then received its first message was stored twice in its list, and removing it (for example when the user is removed from the channel) cleaned up only one entry. The next list query threw on the stale entry, the list stayed loading and stopped updating, and connection recovery skipped it. Locating an item now checks whether the list already holds it before using sort bounds, without scanning for new or unmoved items.
  • 65d34077: Fixes an issue where truncating a channel kept its last message preview and its position in the list. The server clears last_message_at on truncation; the paginator now recomputes the last message from what remains, drops a seeded last-message time older than the truncation, and channel.truncated applies the event's channel data.
  • 0373a2d6: Fixes an issue where a hidden channel did not come back to the list on a new message. The server unhides a channel on any new message without sending channel.visible; message.new and notification.message_new now clear hidden before the lists route the event.
  • 9878b23e: Fixes an issue where lists sorted by last_updated moved a channel to the top when its data was updated. The server's last_updated is the last message time, else the creation time; it does not use updated_at.
  • a87bba04: Fixes an issue where the channel preview's last message did not update for changes that do not go through ingestion: soft deletes, reactions and other writes to the stored message by other holders, and an author rename. The message paginator now refreshes its last message from the store when it changes.
  • 5794effe: Fixes an issue where hard-deleting a channel's newest message updated the preview but kept the channel at its old position until the next query. The server moves last_message_at back to the previous message; the paginator now does the same with the previous loaded message, and keeps the server value when no earlier message is loaded.
  • c58a6090: Fixes an issue where a channel list published a new items array on every channel event (a new message to the top channel, presence, typing) even when the order and membership were unchanged, re-rendering every consumer of the list. The list keeps its current array when the next one holds the same channels in the same order.
  • b34b69f1: Fixes an issue where an error thrown by an event handler was logged without the error itself, only the handler id and index.
  • c4295b29: Fixes an issue where, on an offline cold start, a channel list read its cached first page from the offline database once for every request made before the sync finished (UIs make several on mount), re-hydrating the same channels and re-rendering every row each time. The query waiting for the sync is now remembered, so a repeat request for the same query does nothing: the cache is read once and the network query runs once. A request for a different query still reads the cache for itself and replaces the waiting one.

Changelog

  • Fix message list pagination stopping after jumping to a message, including quoted replies in threads.
  • Fix a channel list getting stuck after the user is removed from a channel that was added while empty.
  • Fix channel list order and previews after truncating a channel, hiding it, hard-deleting its newest message, or updating its data under a last_updated sort.
  • Fix channel previews not reflecting soft deletes, reactions and author renames of the last message.
  • Avoid re-rendering a channel list when an event leaves its order unchanged.
  • Read the offline cache and query the channel list once on an offline cold start.
  • Log the error when an event handler throws.

@isekovanic
isekovanic merged commit 080af2c into release-v10 Oct 13, 2026
4 checks passed
@isekovanic
isekovanic deleted the fix/v10-stability-and-perf-fixes branch October 13, 2026 10:16
isekovanic added a commit to GetStream/stream-chat-react-native that referenced this pull request Oct 13, 2026
## 🎯 Goal

Linear ticket:
https://linear.app/stream/issue/REACT-1226/stability-and-performance-fixes

LLC PR: GetStream/stream-chat-js#1910

Fixes stability and render-performance issues in the channel list,
channel previews, message rows and the SampleApp's offline start. Pairs
with the `stream-chat-js` PR that fixes the client-side half of the
channel list and pagination issues.

## 🛠 Implementation details

* `f076efe12`: Fixes an issue where a presence change re-rendered every
channel preview containing that user (avatars and names included),
although previews do not render presence.
`useChannelMembersState(channel, pick?)` takes an optional `pick` that
selects the member fields a consumer renders; the members object is only
replaced when a picked field changes. The default preview hooks
(`useChannelPreviewDisplayName`, `ChannelAvatar`, `useIsDirectChat`)
pass their own picks. Without `pick` the hook behaves as before.
* `72b8fd705`: Fixes an issue where opening the new-message screen and
picking a user created the channel on the server before anything was
sent. A draft channel has no id and is marked initialized, and
`<Channel>` queried it on mount, which creates it. `<Channel>` now skips
the mount query for a draft.
* `111785981`: Fixes an issue in the SampleApp where a cold start while
offline with a token provider failed to fetch a token, disconnected the
user and never recovered. The SampleApp now sets
`persistUserOnConnectionFailure`, and its token provider falls back to
the last token it fetched for that user on a network error (the token is
cleared on logout; HTTP errors still throw).
* `399be160a`: Fixes an issue where opening or closing a thread
re-rendered every message row in the channel. The message input context
was rebuilt whenever the thread changed, and every row reads it. Nothing
in that context depends on the thread any more, so the dependency is
gone.
* `cde3f4dc5`: Fixes an issue where the channel list asked for a next
page before its first page had loaded (an empty list reaches its end as
soon as it renders). `loadNextPage` now does nothing until the list has
been queried once.

Public API notes:
- `useChannelMembersState` gains an optional second parameter. Additive.
- `useCreateMessageInputContext` no longer takes `threadInstance`.
Passing it in an object literal is now a TypeScript error.

## 🎨 UI Changes

## 🧪 Testing

## ☑️ Checklist

- [ ] I have signed the [Stream
CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform)
(required)
- [x] PR targets the `develop` branch
- [ ] Documentation is updated
- [ ] New code is tested in main example apps, including all possible
scenarios
  - [ ] SampleApp iOS and Android
  - [ ] Expo iOS and Android
github-actions Bot pushed a commit that referenced this pull request Oct 16, 2026
## [10.0.0-rc.22](v10.0.0-rc.21...v10.0.0-rc.22) (2026-10-16)

### ⚠ BREAKING CHANGES

* `StreamChatOptions` and `client.options` are removed.
`new StreamChat(key, config)` and `StreamChat.getInstance(key, config)` take
the configuration tree (`DeepPartial<InstanceConfigTree>`) as their second
argument; the `config` wrapper is dropped.
Option moves:
- `allowServerSideConnect`, `axiosRequestConfig`, `baseURL`, `browser`,
  `persistUserOnConnectionFailure` -> `client.<same name>`
- `notifications` -> `client.notificationManager`
- top-level axios fields (`timeout`, `httpsAgent`, ...) ->
  `client.axiosRequestConfig.<key>`
Example: `new StreamChat(key, { client: { allowServerSideConnect: true } })`.
`client.persistUserOnConnectionFailure` is no longer a field (use
`client.config.setConfig('client', { persistUserOnConnectionFailure })`);
`client.browser` and `client.node` are read-only getters.
`baseURL`, `axiosRequestConfig` and `notificationManager` are read at
construction, and the tree copies `axiosRequestConfig` instead of keeping
your object. See v9-to-v10-migration-guide-client-construction.md.

### Bug Fixes

* don't override local message attachments in createLinkPreviewsCo… ([#1885](#1885)) ([2aa5144](2aa5144))
* ensure API errors parsing works even with multiple axios copies ([#1909](#1909)) ([e0cfba9](e0cfba9))
* stability and perf fixes ([#1910](#1910)) ([080af2c](080af2c))
* type fixes from docs check; add docs snippet runner ([#1902](#1902)) ([2095fc1](2095fc1))
* type issues from platform docs check; add docs snippet test for the platform docs ([#1914](#1914)) ([c7706d2](c7706d2))
* **types:** add before_message_send_hook_system_messages to app settings response ([#1887](#1887)) ([724b4f7](724b4f7))

### Features

* add poll translation i18n fields ([#1878](#1878)) ([9d396e5](9d396e5)), closes [GetStream/chat#17029](https://github.com/GetStream/chat/issues/17029)
* poll optimistic updates ([#1895](#1895)) ([e3dac59](e3dac59))
* replace StreamChatOptions with the configuration tree ([#1911](#1911)) ([f05b861](f05b861))
@stream-ci-bot

Copy link
Copy Markdown

🎉 This PR is included in version 10.0.0-rc.22 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants