Channel details contexts
The contexts of channel details. ChannelDetailsContextProvider holds the channel every part of the screen reads; you render it. The forms and lists render the other providers themselves, each holding a search source or a store. This page lists each provider's props and value. The hooks that read them are on Channel details hooks.
Best practices
- Render
ChannelDetailsContextProvideraroundChannelDetails, and around every screen of your own that renders a form or a list of channel details, with the same channel. - Don't render the list providers yourself to use a list, since the lists render their own. Render a provider when you build a list of your own on its search source, or pass
searchSourceto the list. - Create a search source of your own once, with
useState(() => ...), and activate it. The providers use the source they get as it is. - Read a source's results with
useStateStore(searchSource.state, selector)and a selector at module scope.
Overview
| Provider | Rendered by | Value | Hook |
|---|---|---|---|
ChannelDetailsContextProvider |
your app | { channel, closeModals, signalStore } |
useChannelDetailsContext() |
ChannelEditDetailsProvider |
ChannelEditDetailsForm |
{ store, submit, compressImageQuality, doFileUploadRequest } |
useChannelEditDetailsContext() |
ChannelAddMembersProvider |
ChannelAddMembersForm |
{ searchSource, selectionStore, submit } |
useChannelAddMembersContext() |
ChannelMemberListProvider |
ChannelMemberList |
{ searchSource } |
useChannelMemberListContext() |
ChannelPinnedMessageListProvider |
PinnedMessageList |
{ searchSource } |
useChannelPinnedMessageListContext() |
ChannelMediaListProvider |
MediaList |
{ searchSource } |
useChannelMediaListContext() |
ChannelFileAttachmentListProvider |
FileAttachmentList |
{ searchSource } |
useChannelFileAttachmentListContext() |
Every hook throws outside its provider. The edit and add members providers read the channel from ChannelDetailsContextProvider, so they need it around them. The list providers take the channel as a prop. Each context is also exported, as ChannelDetailsContext, ChannelEditDetailsContext and so on.
ChannelDetailsContextProvider
| Prop | Type | Default | Description |
|---|---|---|---|
channel |
Channel |
required | The channel the screens show. |
children |
ReactNode |
The screen. |
ChannelDetailsContextValue:
| Value | Type | Description |
|---|---|---|
channel |
Channel |
The channel passed to the provider. |
closeModals |
() => void |
Closes every modal channel details opened inside this provider, such as the member list. Call it before you navigate away from one. |
signalStore |
SignalStore |
The store closeModals() signals through. Its state holds signal, which turns true and back to false on each call. |
The value changes when the provider gets another channel. A new channel instance under the same cid counts as another channel.
ChannelEditDetailsProvider
ChannelEditDetailsForm renders it around the edit form, with the form's compressImageQuality and doFileUploadRequest. It's also a notification target in the channel-details panel, so the notifications of saving show in the form.
ChannelEditDetailsProviderProps:
| Prop | Type | Default | Description |
|---|---|---|---|
compressImageQuality |
number |
From 0 to 1, the quality a picked or taken image is compressed to. Without it, the image isn't compressed. | |
doFileUploadRequest |
GlobalFileUploadRequest |
client.uploadImage() |
Uploads the new image and returns { file }, the URL to save. |
children |
ReactNode |
The form. |
ChannelEditDetailsContextValue:
| Value | Type | Description |
|---|---|---|
store |
EditChannelDetailsStore |
The form's state. |
submit |
() => Promise<void> |
Saves the name and the image, the ones that changed, with Channel.updatePartial(). Rejects with an AggregateError when one fails. |
compressImageQuality |
number |
As passed to the provider. |
doFileUploadRequest |
GlobalFileUploadRequest |
As passed to the provider. |
An empty name unsets the channel's name, and a removed image unsets its image. Each save publishes a success or failure notification.
EditChannelDetailsStore
The provider creates the store once, from the channel's name and image at that moment, so a channel.updated event doesn't overwrite what the user is typing. Mount the provider once for each edit.
| Field | Type | Description |
|---|---|---|
currentName |
string |
The name in the field. |
initialName |
string |
The channel's name when the form opened, custom.name, or ''. |
initialImage |
string | undefined |
The channel's image when the form opened, custom.image. |
updatedImage |
File | null | undefined |
undefined while untouched, the picked File, or null once the image is removed. |
pendingAction |
EditChannelImagePendingAction | null |
'camera', 'library' or 'reset', picked in the image sheet and run once the sheet has closed. |
setCurrentName(name), setUpdatedImage(image) and setPendingAction(action) change them. useIsNameEdited(store), useIsImageEdited(store) and useAreChannelDetailsEdited(store) say whether anything changed, and re-render only when the answer does.
ChannelAddMembersProvider
ChannelAddMembersForm renders it around the add members form, with the form's searchSource. It's also a notification target in the channel-details panel.
ChannelAddMembersProviderProps:
| Prop | Type | Default | Description |
|---|---|---|---|
searchSource |
UserSearchSource |
users, sorted by name | The source of the users to add. It's used as it is, so activate it and set its sort yourself. |
children |
ReactNode |
The form. |
The default source loads 25 users a page, searches with name: { $autocomplete: query }, and lists every user while the query is empty.
ChannelAddMembersContextValue:
| Value | Type | Description |
|---|---|---|
searchSource |
UserSearchSource |
The source of the list. |
selectionStore |
SelectionStore |
The ids of the selected users, in state.selectedIds. select(id), deselect(id) and toggle(id) change them. |
submit |
() => Promise<void> |
Adds the selected users with Channel.addMembers({ members }). Rejects when the request fails. |
useIsSelected(selectionStore, id) and useIsSelectionEmpty(selectionStore) read the selection, and re-render only when their answer changes.
The list providers
ChannelMemberListProvider, ChannelPinnedMessageListProvider, ChannelMediaListProvider and ChannelFileAttachmentListProvider take the same props:
| Prop | Type | Default | Description |
|---|---|---|---|
channel |
Channel |
required | The channel the default source is for. |
searchSource |
ChannelMemberSearchSource or MessageSearchSource |
the default source below | The source to provide instead. |
children |
ReactNode |
The list. |
Their value is { searchSource }. The provider creates the default source when it mounts, even when you pass your own, and keeps it for as long as it's mounted. A list renders the provider with the list's own searchSource prop. The provider builds a new value object each time it renders.
| Provider | Default source |
|---|---|
ChannelMemberListProvider |
A ChannelMemberSearchSource of the channel, sorted by name, searched with name: { $autocomplete } |
ChannelPinnedMessageListProvider |
A MessageSearchSource with cid of the channel and pinned: true, searched with text: { $q } |
ChannelMediaListProvider |
A MessageSearchSource with cid of the channel and attachments.type in image and video, newest first |
ChannelFileAttachmentListProvider |
A MessageSearchSource with cid of the channel and attachments.type of file or audio, newest first |
Each loads 25 items a page and allows an empty query. The sources don't follow events. A source shows what the server returned when it last queried.
MessageSearchSource and ChannelMemberSearchSource come from stream-chat. Search sources explains their filters, sort and paging.
Example
A photos screen without videos, with a source of your own passed to MediaList:
import { useState } from "react";
import { View } from "react-native";
import { MessageSearchSource } from "stream-chat";
import type { Channel as StreamChannel } from "stream-chat";
import {
ChannelDetailsContextProvider,
MediaList,
useChatContext,
} from "stream-chat-react-native";
export const ChannelPhotosScreen = ({
channel,
}: {
channel: StreamChannel;
}) => {
const { client } = useChatContext();
const [searchSource] = useState(() => {
const source = new MessageSearchSource(client, {
allowEmptySearchString: true,
pageSize: 25,
resetOnNewSearchQuery: false,
});
source.messageSearchChannelFilters = {
cid: channel.cid,
members: undefined,
};
source.messageSearchFilters = {
"attachments.type": "image",
type: undefined,
};
source.messageSearchSort = [{ field: "created_at", direction: -1 }];
source.activate();
return source;
});
return (
<ChannelDetailsContextProvider channel={channel}>
<View style={{ flex: 1 }}>
<MediaList searchSource={searchSource} />
</View>
</ChannelDetailsContextProvider>
);
};members: undefined and type: undefined drop the filters MessageSearchSource adds by default. The grid still shows only the images and videos of the messages it gets, so a message with an image and a video shows both.
Related
- ChannelDetails: the screen.
- Channel details lists: the lists and forms that render these providers.
- Channel details hooks: the hooks that read them.