Info:
This is release candidate documentation for Stream Chat React Native SDK v10. For the latest stable version, see the latest version (v9).

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 ChannelDetailsContextProvider around ChannelDetails, 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 searchSource to 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:

src/ChannelPhotosScreen.tsx
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.