Channel details hooks
These hooks build the channel details screen and the screens it opens: the profile, the navigation rows, the members, the actions, the media, file and pinned message lists, the edit form and the add members form. ChannelDetails uses them, and they're exported for screens of your own. They're exported from stream-chat-react-native and stream-chat-expo.
The screen and its parts are on Channel details, its lists on Channel details lists, and its contexts on Channel details contexts. The feature is on Channel details and members.
Each entry gives the signature, then:
- Returns: what the hook gives back.
- Reads: the store or the context it reads.
- Re-renders: what makes the component render again.
- Needs: where the component must sit, and what the hook does outside that place.
useChannelDetailsContext
Returns the channel the details screens show.
useChannelDetailsContext(): ChannelDetailsContextValue- Returns:
channel: the channel passed toChannelDetailsContextProvider.closeModals(): closes the screens channel details opened on top of itself, such as the full member list. Call it before you navigate away.signalStore: the storecloseModals()signals through, which those screens listen to.
- Reads: the context of
ChannelDetailsContextProvider. No store. - Re-renders: when the provider gets another channel.
- Needs: a
ChannelDetailsContextProvider, which you render aroundChannelDetails. Throws outside it.
useChannelDetailsActionItems
Returns the actions the channel details screen lists.
useChannelDetailsActionItems(params?: {
getChannelActionItems?: GetChannelActionItems;
onChannelDismiss?: () => void;
}): ChannelActionItem[]- Returns: the channel action items for the
detailssurface, fromuseChannelActionItems, aftergetChannelActionItemschanged them. The items with the IDleave,deleteChannelorblockalso callonChannelDismissafter they succeed, so the app can leave a screen whose channel is gone. - Reads: the channel from
useChannelDetailsContext(), its membership, mute state and the blocked users, asuseChannelActionItemsdoes. - Re-renders: when one of the items changes, such as after the channel is muted or pinned.
- Needs:
Chatand aChannelDetailsContextProvider. Throws outside them.
In a direct chat, the block item becomes "Unblock User" once the user is blocked, and keeps the block ID, so a successful unblock calls onChannelDismiss too. In channel details explains the items.
useChannelDetailsNavigationItems
Returns the rows of the navigation section: pinned messages, photos and videos, and files.
useChannelDetailsNavigationItems(params?: {
getNavigationItems?: GetChannelDetailsNavigationItems;
}): ChannelDetailsNavigationItem[]- Returns: one
{ section, label, Icon, onPress? }for each row. The default rows arepinned-messages,photos-and-videosandfiles, with translated labels and the icons ofComponentsContext.getNavigationItems({ context, defaultItems })returns the rows to render instead: add, remove or reorder rows, or setonPressto route a row elsewhere. A row withoutonPressopens the SDK's screen for its section. - Reads:
ComponentsContextand the translation context. No store. - Re-renders: when
getNavigationItems, the icons or the language change. DefinegetNavigationItemsat module scope. - Needs:
Chat. Throws outside it.
useChannelDetailsMemberStatusText
Returns the status line under the channel's title.
useChannelDetailsMemberStatusText(channel: Channel): string- Returns: in a direct chat, "Online" while the other member is online, and
''otherwise. In a group, "5 members, 2 online", from thechannelDetails.presence.membersOnline.labelkey. - Reads:
channel.state, fieldsmembers,memberCountandwatcherCount. - Re-renders: when one of those fields changes, presence changes included.
- Needs:
Chat. Throws outside it.
The online count is the channel's watcher count, as in useChannelOnlineMemberCount.
useChannelDetailsMembersPreview
Returns the first members of a channel, for a section that shows a few and links to the rest.
useChannelDetailsMembersPreview(channel: Channel, max?: number): {
hasMore: boolean;
total: number;
visible: ChannelMemberResponse[];
}- Returns:
visible: the firstmaxloaded members, 5 by default.total: the member count, or the number of loaded members when the count is0.hasMore: whethertotalis abovemax.
- Reads:
channel.state, fieldsmembersandmemberCount. - Re-renders: when the members or the count change.
- Needs: nothing.
useMemberRoles
Returns the role badges of a member row.
useMemberRoles(member: ChannelMemberResponse, getMemberRoles?: GetMemberRoles): RoleLabel[]-
Returns: the roles, each
{ key, label }, in this order:owner, when the member created the channel;admin, when the user's app role isadmin;moderator, when the member'schannel_roleischannel_moderator.
getMemberRoles({ channel, defaultRoleLabels, member, t })returns the roles instead,[]for none. -
Reads: the channel from
useChannelDetailsContext(), and the translation context. No store. -
Re-renders: never by itself.
-
Needs:
Chatand aChannelDetailsContextProvider. Throws outside them.
useChannelMemberActionItems
Returns the actions offered for one member.
useChannelMemberActionItems(params: {
channel: Channel;
member: ChannelMemberResponse;
getChannelMemberActionItems?: GetChannelMemberActionItems;
}): ChannelMemberActionItem[]- Returns: the member's action items, after
getChannelMemberActionItemschanged them. For another member, the items mute or unmute, and block or unblock, the user. With theupdate-channel-memberscapability, an item also removes the member from the channel. Blocking and removing ask for confirmation first. The current user's own row has no items. - Reads:
channel.state(ownCapabilities),client.mutedUsersStoreandclient.blockedUsers. - Re-renders: when the capabilities change, and when the member is muted, unmuted, blocked or unblocked.
- Needs:
Chat. Throws outside it.
Member actions explains the items and builds a member sheet on them.
useUserActions
Returns the actions that act on one user.
useUserActions(user: UserResponse | undefined): UserActions- Returns:
{ muteUser, unmuteUser, blockUser, unblockUser }. Each takes{ onSuccess?, onFailure? }, publishes a success or failure notification, and does nothing without a user. - Reads: no store.
- Re-renders: never by itself. The functions keep their identity.
- Needs:
Chat. Throws outside it.
The handlers never call onFailure. A failed unblockUser publishes the "Failed to block user" notification, with the type api:user:block:failed.
useUserActivityStatus
Returns a user's presence as text.
useUserActivityStatus(user?: UserResponse): string- Returns: "Online" while the user is online. Otherwise the time they were last active, formatted with the
timestamp.UserActivityStatustranslation key, such as "Last seen 10 minutes ago". "Offline" when the user has nolast_active. - Reads: the user's
onlineandlast_active, and the translation context. No store. - Re-renders: never by itself. It follows the
useryou pass. - Needs:
Chat. Throws outside it.
useEditChannelImage
Returns the functions that take or pick a new channel image.
useEditChannelImage(): {
pickImageFromNativePicker: () => Promise<File | undefined>;
takePhoto: () => Promise<File | undefined>;
}-
Returns:
takePhoto(): opens the camera and resolves to the photo.pickImageFromNativePicker(): opens the native image picker for one image and resolves to it.
Both compress the image with
compressImageQualityfrom the edit context, and resolve toundefinedwhen the user cancels. When access is denied, they show an alert that offers to open the settings, and resolve toundefined. Neither uploads the image:submit()of the edit context does. -
Reads:
compressImageQualityfromuseChannelEditDetailsContext(). -
Re-renders: never by itself.
-
Needs:
Chatand aChannelEditDetailsProvider. Throws outside them.
useMediaList
Turns messages into one tile per image or video attachment.
useMediaList(messages?: MessageResponse[]): { attachment: Attachment; message: MessageResponse }[]- Returns: a tile for each image or video attachment of the messages, in message order. Link previews are left out.
- Reads: its argument only.
- Re-renders: never by itself.
- Needs: nothing.
The media screen passes it the items of its search source.
useFileAttachmentListSections
Groups the file attachments of messages by month.
useFileAttachmentListSections(messages?: MessageResponse[]): {
data: { attachment: Attachment; message: MessageResponse }[];
title: string;
}[]- Returns: sections in message order, each titled with the month of its messages, formatted with the
timestamp.FileAttachmentListSectiontranslation key. A section holds one tile for each file or audio attachment. Link previews are left out. - Reads: its argument, and the translation context.
- Re-renders: when the language changes.
- Needs:
Chat. Throws outside it.
The lists of channel details
Each list screen provides its search source through a context. Read the results from the source's state with useStateStore: items, isLoading, hasNext, searchQuery and lastQueryError.
| Hook | Returns | Provided by |
|---|---|---|
useChannelMemberListContext() |
{ searchSource }: a ChannelMemberSearchSource of the channel's members, sorted by name |
ChannelMemberList, ChannelMemberListProvider |
useChannelMediaListContext() |
{ searchSource }: a MessageSearchSource of the channel's messages with images or videos, newest first |
MediaList, ChannelMediaListProvider |
useChannelFileAttachmentListContext() |
{ searchSource }: a MessageSearchSource of the channel's messages with files or audio, newest first |
FileAttachmentList, ChannelFileAttachmentListProvider |
useChannelPinnedMessageListContext() |
{ searchSource }: a MessageSearchSource of the channel's pinned messages |
PinnedMessageList, ChannelPinnedMessageListProvider |
useChannelAddMembersContext() |
{ searchSource, selectionStore, submit }: a UserSearchSource sorted by name, the selected user IDs, and submit(), which adds the selected users and rejects when the request fails |
ChannelAddMembersForm, ChannelAddMembersProvider |
useChannelEditDetailsContext() |
{ store, submit, compressImageQuality, doFileUploadRequest }: the form's store, and submit(), which saves the edited name and image and rejects with an AggregateError when one of them fails |
ChannelEditDetailsForm, ChannelEditDetailsProvider |
Each throws outside its provider. The list providers pass a new value each time they render. Each provider except ChannelEditDetailsProvider takes a searchSource prop of your own, which replaces the default source with its filters.
The forms keep their state in two stores, with a hook for each question:
| Hook | Returns |
|---|---|
useIsSelected(selectionStore, id) |
whether the user with that ID is selected in the add members form |
useIsSelectionEmpty(selectionStore) |
whether no user is selected |
useIsNameEdited(store) |
whether the name in the edit form differs from the channel's name when the form opened |
useIsImageEdited(store) |
whether the image was picked or removed |
useAreChannelDetailsEdited(store) |
whether either was |
Each re-renders only when its answer changes. The edit store takes the channel's name and image when the form opens, so a channel.updated event doesn't overwrite what the user is typing.
Example
A header of your own for the channel details screen:
import { Text, View } from "react-native";
import {
useChannelDetailsContext,
useChannelDetailsMemberStatusText,
useChannelPreviewDisplayName,
} from "stream-chat-react-native";
export const DetailsHeader = () => {
const { channel } = useChannelDetailsContext();
const title = useChannelPreviewDisplayName(channel);
const status = useChannelDetailsMemberStatusText(channel);
return (
<View style={{ alignItems: "center", padding: 16 }}>
<Text accessibilityRole="header">{title}</Text>
{status ? <Text>{status}</Text> : null}
</View>
);
};Pass it to WithComponents as ChannelDetailsProfile. Whether the current user may edit the channel or add members is on Channel and thread hooks: useCanEditChannel and useCanAddMembersToChannel.