stream-chat-react-native v10.0.0
v10 rebuilds the React Native SDK on stream-chat v10. The SDK no longer keeps its own copy of channel, message, thread and channel-list state; components read from the client's state stores and paginators instead. Threads render as standalone components, the channel list is driven by a paginator your app owns, and connection handling, recovery and optimistic updates come from the client. The release also adds an i18n layer with typed keys and new voice-agent visualizations.
This release covers stream-chat-react-native, stream-chat-expo and stream-chat-react-native-core.
Important
v10 moves to stream-chat@^10.0.0 and has many breaking changes. Before you upgrade, read the v9 → v10 migration guide. Every break is listed in the breaking changes reference, and the translation changes have their own i18n migration guide. Because v10 also moves to stream-chat v10, read the stream-chat v10 release notes as well.
✨ Highlights
Built on stream-chat v10 state
- The SDK no longer keeps a copy of channel state. Components read from
channel.stateand the paginators throughuseStateStore(),useChannel()anduseMessagePaginator(). MessageListandMessageFlashListpage the paginator they render, either the channel's or, inside a thread, the thread's. They track their own loading state, so theloadMore/hasMoreprops are gone. Old messages are pruned from memory as the list grows.useMessageOperations()handles sending, editing and deleting messages, and reactions. All of them are optimistic and roll back if they fail. Before v10, reactions were only optimistic with offline support enabled.- Request handlers for send, update, mark-read and uploads are registered once on the client through
client.config. The<Channel>request props are gone.
Threads as standalone components
<Thread thread={thread}>takes aThreadinstance fromclient.threads.ensure(), renders next to<Channel>instead of inside it, and renders its children:<Thread thread={thread}><MessageList /><MessageComposer /></Thread>.- Threads have their own paginator, unread state and reconnect recovery. Thread list rows always show the latest reply.
Channel list driven by a ChannelPaginator
<ChannelList>takes aChannelPaginatorthat your app creates and registers withclient.channelManager. Filters, sort and the request override live on the paginator, so the same lists are shared across screens.- Lists follow their
filters/sortand reconcile after a reconnect. Channel rows re-render only when their own channel changes, preview data is reactive, and drafts with only attachments show in the preview.
Connectivity and recovery
- New
useNetworkConnectionState(),useWSConnectionState()anduseSettledWSConnectionHealth()hooks.<Chat>registers the NetInfo status reporter for you. - The network indicator tells a dropped socket ("Reconnecting...") apart from the device being offline ("Waiting for network...").
- After a reconnect, the client reloads the channels and threads you have open, and unsent messages survive the rebuild.
Messages and composer
- Sending and editing go through
messageComposer.send()/update(). The client waits for pending uploads before sending, which you turn on withmessageComposer.attachments.pendingUploadsEnabled. - The command middlewares are installed by default, so typing
/giphy catsworks with no setup. - Delivery and read status come from the client's receipts.
MessageStatusshowsread/deliveredand works them out by default. - Jumping to a message, highlighting it and returning to the latest messages are built on the paginator. Use
useIsTargetedMessage(id)to read the highlight anduseJumpToLatestOnOpen()to jump on open. - The
messageActionsfunction runs only when a message's menu opens, not on every render of every row.
i18n
- The translation runtime is shared with React and the JS client through
@stream-io/i18n. - Translation keys are stable dotted identifiers, and
t()is typed to the catalog. UseasDynamicKey()for your own app keys. - Only English is bundled. Register other languages yourself.
AI components
- New
VoiceWaveandVoiceGlowvisualizations for voice agents.
Performance
ChatContextholds onlyclient,getAppSettingsandisMessageAIGenerated. Its consumers no longer re-render on mute changes or when the app returns from the background.<Channel>no longer re-renders on channel updates that leave its capabilities unchanged.- Attachment picker cells re-render only when their own selection changes, not on every upload progress tick.
- The first message page loads 25 messages instead of about 100.
⚠️ Breaking changes
These are the most common changes. The breaking changes reference has the full list, with a migration for each.
Dependencies and platform
stream-chatmoves to^10.0.0. If your app depends onstream-chatdirectly, move it to the same major.- The
react-nativepeer is now>=0.79(Metro ≥0.82 is needed for packageexports), and theexpopeer is now>=53. stream-chatrequires Node>=22.18.0at install time. Yarn 1 refuses to install the package on older Node versions.@stream-io/i18nis a new dependency, andi18nextis no longer a direct dependency.dayjsmoves to^1.11.23and must resolve to a single copy.- Import
StateStorefrom@stream-io/state-store, and make sure the app resolves only one copy. - The offline database is rebuilt. On the first launch after the upgrade, the SQLite cache is wiped and recreated, which also drops v9's queued offline writes. Dates are now stored as unix nanoseconds.
<Chat> and contexts
ChatContextholds only{ client, getAppSettings, isMessageAIGenerated }.channel,setActiveChannel,isOnline,connectionRecovering,appSettings,mutedUsersandenableOfflineSupportare removed. Use the connection hooks,getAppSettings(),useMutedUsers()and your own navigation state instead.TypingContext,PaginatedMessageListContextandDebugContextare removed. Read typing fromchannel.stateand messages fromuseMessagePaginator().ChannelContextno longer providesmembers,read,watchers,markRead,targetedMessage,loadChannelAroundMessage,reloadChannel,loadingorerror. UseuseStateStore(channel.state, …),useMarkRead()and the paginator'sjumpToMessage()/jumpToTheFirstUnreadMessage()/stateinstead.MessagesContextno longer providessendReaction,deleteReaction,deleteMessage,retrySendMessageorupdateMessage. UseuseMessageOperations()instead.useCreateChatClienttakes the stream-chat configuration tree ({ client: { … } }) instead ofStreamChatOptions.
<Channel>
messages,loadingMore,threadMessages,messageId,threadandthreadListare removed. Jump withchannel.messagePaginator.jumpToMessage(), and render<Thread>next to<Channel>.doSendMessageRequest,doUpdateMessageRequest,doMarkReadRequest,preSendMessageRequestanddoFileUploadRequestare removed. Register them withclient.configunderchannel.requestHandlersandmessageComposer.attachments.doUploadRequest(withcustomCdn: true).maximumMessageLimit,stateUpdateThrottleInterval,allowSendBeforeAttachmentsUploadandenableOfflineSupportmoved intoclient.config. Offline support is set on<Chat>.<Channel>no longer listens for events, resyncs on reconnect or unmounts when the channel is deleted. The client reloads active channels, and your app decides what to show fromchannel.pendingDisposal.
<ChannelList>
- The
paginatorprop is required.filters,sort,options,lockChannelOrderandqueryChannelsOverridemove onto theChannelPaginator. Your app removes and disposes the paginator on logout. - The event-handler props (
onNewMessage,onChannelUpdated,onAddedToChannel, …) are removed. Membership and order follow the paginator's filters and sort. Customize global behavior withclient.channelManager.addEventHandler(). ChannelsContextno longer provideschannels,hasNextPage,loadingChannelsorrefreshing. Read the list'spaginatorinstead.loadNextPage()takes no arguments.
Threads
<Thread>requires aThreadinstance asthread, not the parent message, and renders its children.closeThread,loadMoreThread,additionalMessageListProps,additionalMessageComposerPropsand similar props are removed; configure the list and composer through their own props.ThreadContextis now{ thread?: Thread, allowThreadMessagesInChannel }.onThreadSelectreceives aThreadinstead of a message.ThreadTypeis removed.- The
ThreadMessageComposerandMessageListcomponent slots are removed.
Messages and message lists
MessageList/MessageFlashListdroploadMore,loadMoreRecent,hasMore,threadList,targetedMessage,channelUnreadStateStoreand the other state props. Thethreadprop is now aThreadinstance.- The
handle*action props,messageActionsandsupportedReactionson<Message>are removed. Set them on<Channel>and customize per message through themessageActionsfunction.useMessageActions()/useMessageActionHandlers()take no arguments. MessageStatustakesread/deliveredbooleans instead ofreadBy/deliveredToCount.- Removed hooks:
useTargetedMessage(useuseIsTargetedMessage),useIsOnline(nowuseConnectionLifecycle),useAppSettings,useClientMutedUsers(useuseMutedUsers),useChannelUpdatedanduseSelectedChannelState. setupCommandUIMiddlewaresand the SDK's attachment composition middlewares are removed, because stream-chat installs its own by default.
i18n
- The built-in dictionaries (
enTranslations,esTranslations,frTranslations, …) are no longer exported or bundled. - Translation keys were renamed to dotted keys; every v9 key is listed in the key map. Old keys silently stop matching.
- The
Streami18nAPI changed: the constructor takesi18nextConfigOverrides,setLanguage()resolves tovoid, andgetTranslators()is replaced byinit().
Data shapes (from stream-chat v10)
- Custom fields are stored under
custom:channel.data.custom.name,message.custom.*and attachmentcustom.mime_type/duration/waveform_data. - Server timestamps are
TimestampNS(unix nanoseconds), so convert them before formatting. - Sort is
SortParamRequest[], and filters use'custom.<field>'keys. - Message moderation data is in
message.moderation.
🐛 Notable fixes
- Message list: fixed snapping when sending a message and pagination past a certain page. A failed page no longer blocks pagination at that end of the list, and removing a message no longer scrolls to the bottom. The "new messages" separator no longer sticks after returning from a thread.
- Unread state: unread counts come from one place. Opening a thread no longer marks the channel read, and a thread with no replies is not marked read.
- Composer: text from a cancelled edit no longer carries over into the next edit. Edits are optimistic again and are stored offline. The commands button and the send-disallowed indicator update when capabilities or config change.
- Offline: unsent messages survive closing the app. The offline channel guard works,
message_limitis respected when querying the database, and required timestamps from the offline store are guarded. - Channel list: the footer no longer flickers during pagination. A mounted list reloads after the user reconnects, and changes to config props take effect at runtime.
- Misc:
<Chat>follows the connected user reactively, the offline header shows correctly on a cold start, and the SDK no longer imports axios directly.
📚 Migration resources
- AI-assisted migration guide: v9 → v10
- Full breaking changes reference
- i18n migration guide
- stream-chat v10 release notes
Full changelog: v9.12.1...v10.0.0