npm stream-chat-expo 10.0.0
v10.0.0

2 hours ago

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.state and the paginators through useStateStore(), useChannel() and useMessagePaginator().
  • MessageList and MessageFlashList page the paginator they render, either the channel's or, inside a thread, the thread's. They track their own loading state, so the loadMore / hasMore props 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 a Thread instance from client.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 a ChannelPaginator that your app creates and registers with client.channelManager. Filters, sort and the request override live on the paginator, so the same lists are shared across screens.
  • Lists follow their filters / sort and 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() and useSettledWSConnectionHealth() 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 with messageComposer.attachments.pendingUploadsEnabled.
  • The command middlewares are installed by default, so typing /giphy cats works with no setup.
  • Delivery and read status come from the client's receipts. MessageStatus shows read / delivered and 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 and useJumpToLatestOnOpen() to jump on open.
  • The messageActions function 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. Use asDynamicKey() for your own app keys.
  • Only English is bundled. Register other languages yourself.

AI components

  • New VoiceWave and VoiceGlow visualizations for voice agents.

Performance

  • ChatContext holds only client, getAppSettings and isMessageAIGenerated. 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-chat moves to ^10.0.0. If your app depends on stream-chat directly, move it to the same major.
  • The react-native peer is now >=0.79 (Metro ≥0.82 is needed for package exports), and the expo peer is now >=53.
  • stream-chat requires Node >=22.18.0 at install time. Yarn 1 refuses to install the package on older Node versions.
  • @stream-io/i18n is a new dependency, and i18next is no longer a direct dependency. dayjs moves to ^1.11.23 and must resolve to a single copy.
  • Import StateStore from @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

  • ChatContext holds only { client, getAppSettings, isMessageAIGenerated }. channel, setActiveChannel, isOnline, connectionRecovering, appSettings, mutedUsers and enableOfflineSupport are removed. Use the connection hooks, getAppSettings(), useMutedUsers() and your own navigation state instead.
  • TypingContext, PaginatedMessageListContext and DebugContext are removed. Read typing from channel.state and messages from useMessagePaginator().
  • ChannelContext no longer provides members, read, watchers, markRead, targetedMessage, loadChannelAroundMessage, reloadChannel, loading or error. Use useStateStore(channel.state, …), useMarkRead() and the paginator's jumpToMessage() / jumpToTheFirstUnreadMessage() / state instead.
  • MessagesContext no longer provides sendReaction, deleteReaction, deleteMessage, retrySendMessage or updateMessage. Use useMessageOperations() instead.
  • useCreateChatClient takes the stream-chat configuration tree ({ client: { … } }) instead of StreamChatOptions.

<Channel>

  • messages, loadingMore, threadMessages, messageId, thread and threadList are removed. Jump with channel.messagePaginator.jumpToMessage(), and render <Thread> next to <Channel>.
  • doSendMessageRequest, doUpdateMessageRequest, doMarkReadRequest, preSendMessageRequest and doFileUploadRequest are removed. Register them with client.config under channel.requestHandlers and messageComposer.attachments.doUploadRequest (with customCdn: true).
  • maximumMessageLimit, stateUpdateThrottleInterval, allowSendBeforeAttachmentsUpload and enableOfflineSupport moved into client.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 from channel.pendingDisposal.

<ChannelList>

  • The paginator prop is required. filters, sort, options, lockChannelOrder and queryChannelsOverride move onto the ChannelPaginator. 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 with client.channelManager.addEventHandler().
  • ChannelsContext no longer provides channels, hasNextPage, loadingChannels or refreshing. Read the list's paginator instead. loadNextPage() takes no arguments.

Threads

  • <Thread> requires a Thread instance as thread, not the parent message, and renders its children. closeThread, loadMoreThread, additionalMessageListProps, additionalMessageComposerProps and similar props are removed; configure the list and composer through their own props.
  • ThreadContext is now { thread?: Thread, allowThreadMessagesInChannel }. onThreadSelect receives a Thread instead of a message. ThreadType is removed.
  • The ThreadMessageComposer and MessageList component slots are removed.

Messages and message lists

  • MessageList / MessageFlashList drop loadMore, loadMoreRecent, hasMore, threadList, targetedMessage, channelUnreadStateStore and the other state props. The thread prop is now a Thread instance.
  • The handle* action props, messageActions and supportedReactions on <Message> are removed. Set them on <Channel> and customize per message through the messageActions function. useMessageActions() / useMessageActionHandlers() take no arguments.
  • MessageStatus takes read / delivered booleans instead of readBy / deliveredToCount.
  • Removed hooks: useTargetedMessage (use useIsTargetedMessage), useIsOnline (now useConnectionLifecycle), useAppSettings, useClientMutedUsers (use useMutedUsers), useChannelUpdated and useSelectedChannelState.
  • setupCommandUIMiddlewares and 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 Streami18n API changed: the constructor takes i18nextConfigOverrides, setLanguage() resolves to void, and getTranslators() is replaced by init().

Data shapes (from stream-chat v10)

  • Custom fields are stored under custom: channel.data.custom.name, message.custom.* and attachment custom.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_limit is 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

Full changelog: v9.12.1...v10.0.0

Don't miss a new stream-chat-expo release

NewReleases is sending notifications on new releases.