Repository navigation
perf: message actions hook invocations - #3866
Merged
Merged
Conversation
Contributor
SDK Size
|
This was referenced Oct 19, 2026
Merged
oliverlaz
added a commit
that referenced
this pull request
Oct 19, 2026
The inventory was taken against V10; the stack underneath this PR adds more public API changes. Re-ran the surface diff and the v9 sample-app compile against the stack tip (refactor/stop-creating-sdk-paginator) and covered them: - v10-breaking-changes.md: standalone <Thread> next to <Channel> (removed Channel thread/threadList/allowThreadMessagesInChannel/shouldSyncChannel, Thread props, threadList everywhere, ThreadMessageComposer slot, ThreadContext shape, onAlsoSentToChannelHeaderPress move), message actions built on demand (argument-less useMessageActions/useMessageActionHandlers, removed Message handleX/messageActions/supportedReactions), and the app-owned <ChannelList paginator> (removed filters/sort/options/ lockChannelOrder/queryChannelsOverride). - ai-migration-v9-to-v10.md: correct the removed Thread prop names (additionalMessageComposerProps, additionalMessageFlashListProps), add shouldSyncChannel, and move R.6 and its quick-reference rows onto the ChannelPaginator. - v10-docs-impact.md: re-scan the docs for the stack's changes (109 pages affected, was 99).
isekovanic
pushed a commit
that referenced
this pull request
Oct 19, 2026
β¦useCreateChatClient (#3871) ## π― Goal Fix the SDK-side problems the v10 public-API audit found (listed in `ai-docs/v10-breaking-changes.md` Β§16 in #3870), so they ship fixed instead of documented as limitations. The docs PR #3870 already drops these known-issue notes from `ai-docs/v10-breaking-changes.md` and `ai-docs/ai-migration-v9-to-v10.md` (Β§13.1, Β§16.1, Β§R.5), so it assumes this PR lands first or together with it. This PR is code only. **Stacked on #3869** (Ivan's stack: #3866 β #3867 β #3868 β #3869). The branch is rebased onto `refactor/stop-creating-sdk-paginator`; until the PR base is moved there, the diff also shows that stack's commits. ## π Implementation details - **`<Channel>` overrode a registered page size.** On every mount it ran `channel.messagePaginator.pageSize = 25` (now in `useChannelLifecycle`, after #3868). That setter is a runtime `updateConfig` patch, which outranks every declarative layer, so a `client.config.set({ channel: { messagePaginator: { pageSize } } })` registration (the migration guide's advice) never took effect. `useChannelLifecycle` now applies the 25-message default only when no `pageSize` is registered under `channel.messagePaginator` or the general `messagePaginator` key, the two places the paginator resolves it from. - **`useCreateChatClient({ userData })` rejected `{ id, name, image }`.** It was typed `OwnUserResponse | UserResponse`, which require server-owned fields (`role`, `created_at`, β¦) in stream-chat v10. It is now `ClientUser`, exactly what `client.connectUser` accepts. The `as UserResponse` casts in ExpoChatGPTSample and ExpoMessaging are gone (ExpoMessaging keeps `as ClientUser` only to narrow away `null`). - **`AGENTS.md`** said the main entry must never reach `@stream-io/state-store`, but the `state-store/` stores and Poll contexts import it at runtime. The rule now matches `package/bin/validate-entry-isolation.js` (`@stream-io/state-store` and `lodash` are shared; only `react-syntax-highlighter`, `@khanacademy/simple-markdown`, `zod`, `victory-native` and Skia are AI-only), and the script path is corrected. ## π¨ UI Changes None. ## π§ͺ Testing - `Channel.test.tsx` (still passes on the rebased base) β "message page size": default 25 with nothing registered, and a registered `channel.messagePaginator.pageSize` / `messagePaginator.pageSize` is kept after mount. The two registration cases fail with the guard removed. - New `useCreateChatClient.userData.test.ts`: a type-level assertion that the hook's `userData` and `connectUser`'s parameter are mutually assignable (it fails `test:typecheck` under the old typing), plus a runtime check that a `{ id, name, image }` user is passed to `connectUser`. - After the rebase onto #3869: `yarn lint`, `cd package && yarn test:typecheck`, and the `Channel` and `useCreateChatClient` suites pass. Before the rebase, locally green: `yarn build`, `yarn lint`, `cd package && yarn test:typecheck`, `yarn typecheck` (covers the example apps without the casts), `yarn test:unit` (2200 passed). ## βοΈ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch (targets `V10`: v10 release fix) - [x] Documentation is updated (`AGENTS.md`; migration docs in #3870) - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android
isekovanic
pushed a commit
that referenced
this pull request
Oct 19, 2026
## π― Goal Collect every breaking change between v9 (`develop`) and v10 (`V10`) in one place, as the source of truth for the v10 migration guide and the docs update. Also verify the running ledger `ai-docs/ai-migration-v9-to-v10.md` and measure the impact on the getstream.io React Native docs. ## π Implementation details - **`ai-docs/v10-breaking-changes.md` (new):** the full list, grouped by surface: dependencies, removed exports, component props, contexts, hooks, utilities, types, classes and stores, slots and theme, i18n, offline DB, `stream-chat` v10 changes RN integrators hit, behavioural changes, deep imports and new APIs. Each entry has a one-line migration and links to the ledger section and PR. - **`ai-docs/v10-docs-impact.md` (new):** per-page impact on `getstream.io/content/docs/chat-sdk/react-native/v9-latest`. 109 of 302 pages are affected: 6 to delete or replace, 22 major rewrites, 56 snippet or prop-table updates and 25 mentions. It also lists about 12 new pages or sections. - **`ai-docs/ai-migration-v9-to-v10.md`:** fixes 23 stale or wrong entries. Examples: - `*WithLocalUpdate` β `channel.messageOperations.*` - there is no `deactivate()`; `activate()` returns its release function - `client.activeChannels` β `client.channelManager` - `queryChannelsOverride` should use `queryChannelsAndHydrate` - `channel.markRead()` vs `markReadViaReporter()` - `dbVersion` goes 16 β 18 - `connection.changed` is no longer dispatched - Β§18.4 described a `channelManager` prop that v9 never had Also adds **Part R** (R.1βR.11) for the gaps the audit found: RN/Expo peer floors, the `ChatContext.isOnline` removal, the delivery-receipt props, more removed context fields and props, behaviour changes in `<Channel>`/`<Thread>`/channel list, `stream-chat` state and client APIs, the offline DB contract, i18n gaps and deep imports. - **`ai-docs/i18n-v10-migration.md`:** two corrections. The app-callable formatter keys were not dead in v9, and the date helpers were deep imports in v9. - **`.claude/plans/v10-breaking-changes.md`:** the audit plan. **How the list was produced:** 1. A TypeScript-compiler snapshot of both public surfaces (about 1,285 exports, with props, context values and class members flattened, plus the referenced `stream-chat` types), diffed mechanically. 2. The v9 `SampleApp` and `ExpoMessaging` type-checked against V10: 0 errors on v9 and 144 on v10, and every error cluster maps to an entry. 3. A review of all 40 PRs merged into `V10`, the `examples/` diff, and the deleted or rewritten tests. 4. A cross-check against the `stream-chat` and `stream-chat-react` v10 breaking-change lists. **Stack: #3866 β #3867 β #3868 β #3869 β #3871 β this PR.** The known-issue notes for the SDK bugs the audit found are removed here because #3871 fixes them. The inventory covers `V10` plus #3866β#3869: the surface diff and the v9 sample-app compile were re-run against the stack tip. ## π¨ UI Changes None (docs only). ## π§ͺ Testing Docs only. `yarn lint` passes. Every replacement API the new file names was checked against the V10 exports and `stream-chat` 10.0.0-rc.22. ## βοΈ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch (targets `V10`) - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios (n/a, docs only)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
π― Goal
Every
Messagerow builds the full set of message actions on every render, even though the action menu is closed almost all of the time.useMessageActionHandlersruns twice per row (once directly and once insideuseMessageActions),useMessageActionsbuilt 15 action objects with icons and translated titles and themessageActionsfunction from<Channel>was called on every render. On top of that we had store subscriptions as well. In other words, lots and lots of wasted JS work.This PR moves the action work to the moment a message's menu opens and removes the per row subscriptions.
π Implementation details
Messagebuilds its handlers once per row with the new internaluseCreateMessageActionHandlers. The handlers hold no subscriptions and read mute, ban and block state and the translated text for Copy when they run.MessageContext.messageActionHandlers. The menu uses the row's handlers instead of building its own. Queued menu actions run after the overlay closes but before the menu unmounts and Edit relies on deferred work (portal settle and keyboard focus) that the menu's unmount cleanup would otherwise cancel.MessageActionListWithActionsincomponents/MessageMenu, which only mounts while a message's overlay is open. It readsmessageActionsfromMessagesContextand passes the finished list to theMessageActionListslot, so customMessageActionListimplementations receive the same props as before.As usual, here's the actual reduction in JS work (measured on Android):
Messagebody JS while opening and scrolling 100 rows (FlatList, 103 renders, median)mutedUsersStoresubscriptions with 100 rows mountedMessagebody JS spent on that mute (median)Breaking changes
useMessageActions()anduseMessageActionHandlers()no longer take arguments and read everything from the contexts of the message they are called in.MessageActionsHookPropsis removed. Both hooks have to be called inside a message, for example in a custom message component or a customMessageActionList.handleXcallbacks andmessageActionspassed directly to<Message>(for example from a customMessageoverride) no longer reach the action menu. They need to be set on<Channel>. Per-message customisation goes through themessageActionsfunction, which receives the message.messageActionsfunction now runs when a message's menu opens instead of on every render of every row.π¨ UI Changes
/
π§ͺ Testing
/
βοΈ Checklist
developbranch