Skip to main content
Version: v4

Customize ChannelList

Let's look at how to make some customizations to ChannelList.

Customizing Event Handlers

ChannelList uses Event Listeners to dynamically update when changes occur. If a new message is received, a user is added to a channel, or other events take place, the ChannelList will update its UI accordingly. It's important to note that filters don't apply to updates to the list from events.

The event type the ChannelList reacts to and its corresponding behavior can be overridden using the appropriate prop.

Event TypeDefault BehaviorProp to override
channel.deletedRemove channel from the listonChannelDeleted
channel.hiddenRemove channel from the listonChannelHidden
channel.truncatedUpdates the channelonChannelTruncated
channel.updatedUpdates the channelonChannelUpdated
channel.visibleAdds the channel to the listonChannelVisible
message.newMoves the channel to top of the listlockChannelOrder
notification.added_to_channelAdds the new channel to the top of the list and starts watching itonAddedToChannel
notification.message_newAdds the new channel to the top of the list and starts watching itonMessageNew
notification.removed_from_channelRemoves the channel from the listonRemovedFromChannel

Let's take an example of ChannelList component for frozen channels.

const filters = {
members: { $in: ['vishal'] },
frozen: true
}

<ChannelList filters={filters} />

The notification.message_new event occurs when a message is received on a channel that is not loaded but the current user is a member of. The default behavior when this event occurs is to query the channel the message is received on, then add the channel to the top of the list, irrespective of filters. Thus, if new message appears in some unfrozen channel which current user is member of, it will be added to the list. This may not be a desired behavior since the list is only supposed to show frozen channels.

In this case you can replace the default functionality by providing a custom onMessageNew function as prop to ChannelList component. onMessageNew receives two parameters when called, setChannels, a setter function for the internal channels state, and event, the Event object received for the notification.message_new event. These parameters can be used to create a function that achieves the desired custom behavior.

const filters = {
members: { $in: ['vishal'] },
frozen: true,
};

const customOnMessageNew = async (setChannels, event) => {
const eventChannel = event.channel;

// If the channel is frozen, then don't add it to the list.
if (!eventChannel?.id || !eventChannel.frozen) return;

try {
const newChannel = client.channel(eventChannel.type, eventChannel.id);
await newChannel.watch();
setChannels(channels => [newChannel, ...channels]);
} catch (error) {
console.log(error);
}
};

<ChannelList filters={filters} onMessageNew={customOnMessageNew} />;

Similarly, events other than notification.message_new can be handled as per application requirement.

Replacing infinite scroll pagination with "Load More" button

ChannelList component accepts the List prop, which is a component to render the list of channels. Default value for this prop is ChannelListMessenger and it consumes ChannelsContext, which provides all the necessary values to implement infinite scroll pagination. This component internally uses FlatList from react-native. And loadNextPage function from ChannelsContext is attached to onEndReached prop of underlying FlatList to allow infinite scroll pagination.

Its possible to override the props on underlying FlatList by providing additionalFlatListProps prop to ChannelList or ChannelListMessenger. Thus "Load More" button can be added as ListFooterComponent for underlying FlatList and infinite scroll pagination can be disabled by overriding the onEndReached prop for FlatList.

"Load More" button should invoke loadNextPage function, when pressed. Additionally, you can use pagination related flags such as loadNextPage, hasNextPage, loadingChannels to handle the visibility of this button.

ChannelList
import { Button } from 'react-native';
import { useChannelsContext } from 'stream-chat-react-native';

const FooterLoadMoreButton = () => {
const { loadingChannels, loadNextPage, hasNextPage } = useChannelsContext();

if (loadingChannels || !hasNextPage) return null;

return <Button title={'Load More'} onPress={loadNextPage} />;
};

<ChannelList
additionalFlatListProps={{
ListFooterComponent: FooterLoadMoreButton,
onEndReached: () => null,
}}
/>;

Did you find this page helpful?