Loading data hooks
These hooks read channel lists, message lists, the thread list and the reminder list. The paginators behind them are explained under State > Loading data: How pagination works, Channel list paginators and Message paginators. How to read state in components is on Reading state in components.
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.
useChannelsContext
Returns the paginator and the settings of the ChannelList around the component.
useChannelsContext(): ChannelsContextValue- Returns:
paginator: theChannelPaginatorpassed toChannelList.loadNextPage(): loads the next page, withChannelPaginator.toTail(). It does nothing until the first page has loaded.reloadList(): clears the list and loads the first page again. The list shows its loading state meanwhile.refreshList(): loads the first page again and keeps the channels on screen meanwhile, as pull to refresh does. A call within 5 seconds of the previous one, or of the list mounting, is ignored, unless the last query failed.onSelect,getChannelActionItems,swipeActionsEnabled,additionalFlatListProps,setFlatListRef,loadMoreThreshold,maxUnreadCount,numberOfSkeletons,mutedStatusPositionandpinnedStatusPosition: theChannelListprops of the same names, with their defaults applied.
- Reads: the context
ChannelListprovides. No store. - Re-renders: when
ChannelListprovides a new value, which happens when one of its props changes. Not when the channels change: read those frompaginator.statewithuseStateStore. - Needs:
ChannelList. Throws outside it.
The props are on ChannelsContext.
The channels of a list
No hook returns the channels. Read them from the paginator's state, which holds items (undefined until the first page loads), isLoading, hasMoreTail, hasMoreHead and lastQueryError. A footer for your own ChannelList component reads it like this:
import { Pressable, Text } from "react-native";
import type { ChannelPaginatorState } from "stream-chat";
import { useChannelsContext, useStateStore } from "stream-chat-react-native";
const footerSelector = (state: ChannelPaginatorState) => ({
hasMoreTail: state.hasMoreTail,
isLoading: state.isLoading,
items: state.items,
lastQueryError: state.lastQueryError,
});
export const ChannelListFooter = () => {
const { loadNextPage, paginator, reloadList } = useChannelsContext();
const { hasMoreTail, isLoading, items, lastQueryError } = useStateStore(
paginator.state,
footerSelector,
);
if (lastQueryError) {
return (
<Pressable accessibilityRole="button" onPress={() => reloadList()}>
<Text>Couldn't load channels. Retry</Text>
</Pressable>
);
}
if (!hasMoreTail) return <Text>{items?.length ?? 0} channels</Text>;
return (
<Pressable
accessibilityRole="button"
disabled={isLoading}
onPress={() => loadNextPage()}
>
<Text>Load more</Text>
</Pressable>
);
};Outside a ChannelList, read the same store on the paginator you created. The paginator's fields are on Channel manager and ChannelPaginator.
useMessagePaginator
Returns the message list of the channel or the thread the component renders in.
useMessagePaginator(): MessagePaginator- Returns:
thread.messagePaginatorinside aThread, otherwisechannel.messagePaginatorof theChannel. It's the listMessageListandMessageFlashListrender. - Reads: the
ThreadandChannelcontexts. No store. - Re-renders: when the thread or the channel in context changes. Not when the messages change: read those from
paginator.statewithuseStateStore. - Needs: a
Channelor aThread. Throws outside both.
import { Text } from "react-native";
import type { MessagePaginatorState } from "stream-chat";
import { useMessagePaginator, useStateStore } from "stream-chat-react-native";
const itemsSelector = (state: MessagePaginatorState) => ({
items: state.items,
});
export const LoadedMessageCount = () => {
const paginator = useMessagePaginator();
const { items } = useStateStore(paginator.state, itemsSelector);
return <Text>{items?.length ?? 0} messages loaded</Text>;
};A message paginator's state publishes at most once every 500 ms by default, as Batched message-list updates explains. Its other stores, unreadStateSnapshot, liveViewState, aggregateState and messageFocusSignal, publish at once. The fields of a message list are on Message paginator, and how it loads on Message paginators.
useIsTargetedMessage
Says whether a message is the one the list jumped to.
useIsTargetedMessage(messageId: string): boolean- Returns:
truewhile the message is the target of the paginator's focus signal.MessagePaginator.jumpToMessage()andMessagePaginator.jumpToTheFirstUnreadMessage()set the signal, and it clears itself after a short time. - Reads:
messageFocusSignalof the paginator fromuseMessagePaginator(), itssignal.messageId. - Re-renders: when the message becomes the target, and when it stops being it. A jump re-renders the row that loses the highlight and the row that gains it, not every row.
- Needs: a
Channelor aThread. Throws outside both.
The default message highlights itself with it. Jumping to a message is explained on Moving between channels, threads and messages.
useThreadsContext
Returns the threads and the settings of the ThreadList around the component.
useThreadsContext(): ThreadsContextValue- Returns:
threads: the loaded threads, fromclient.threads.paginator.state.isLoading:truewhile a page loads and no thread is loaded yet.isLoadingNext:truewhile a page loads and threads are already shown.loadMore(): loads the next page, withclient.threads.paginator.toTail().isFocused,onThreadSelectandadditionalFlatListProps: theThreadListprops of the same names.isFocusedisundefinedwhen the prop isn't passed, althoughThreadListtreats a missing prop astrue.
- Reads: the context
ThreadListprovides.ThreadListsubscribes toclient.threads.paginator.stateand passes the result down. - Re-renders: whenever
ThreadListrenders, since it passes a new value each time. That includes every change to the thread list's loading state and items. - Needs:
ThreadList. Throws outside it.
ThreadList also calls client.threads.activate() while isFocused is true, and client.threads.deactivate() when it becomes false and when the list unmounts. Activating the thread manager loads the first page when the list has none, and reloads it when threads got replies while it was inactive. ThreadListProps types isFocused as required, although it defaults to true. Pass the focus state of the screen, as Thread UI shows.
A thread list of your own, without ThreadList, reads client.threads.paginator.state with useStateStore and activates client.threads itself. Chat starts the thread manager's event handling, so render it inside Chat:
import { useEffect } from "react";
import { FlatList, Pressable, Text } from "react-native";
import type { PaginatorState, Thread, ThreadState } from "stream-chat";
import { useChatContext, useStateStore } from "stream-chat-react-native";
const threadsSelector = (state: PaginatorState<Thread>) => ({
isLoading: state.isLoading,
threads: state.items,
});
const titleSelector = (state: ThreadState) => ({ title: state.title });
const ThreadRow = ({
onPress,
thread,
}: {
onPress: (thread: Thread) => void;
thread: Thread;
}) => {
const { title } = useStateStore(thread.state, titleSelector);
return (
<Pressable accessibilityRole="button" onPress={() => onPress(thread)}>
<Text>{title}</Text>
</Pressable>
);
};
export const CompactThreadList = ({
onThreadPress,
}: {
onThreadPress: (thread: Thread) => void;
}) => {
const { client } = useChatContext();
const { isLoading, threads } = useStateStore(
client.threads.paginator.state,
threadsSelector,
);
useEffect(() => {
client.threads.activate();
return () => client.threads.deactivate();
}, [client]);
if (isLoading && !threads?.length) return <Text>Loading threads...</Text>;
return (
<FlatList
data={threads ?? []}
keyExtractor={(thread) => thread.id}
onEndReached={() => client.threads.paginator.toTail()}
renderItem={({ item }) => (
<ThreadRow onPress={onThreadPress} thread={item} />
)}
/>
);
};The thread list is explained on Replies and threads, and its API on Thread and thread manager.
useQueryReminders
Returns the reminder list, kept in step with reminder events.
useQueryReminders(): {
data: ReminderResponseData[];
isLoading: boolean;
loadNext: () => Promise<void>;
setData: Dispatch<SetStateAction<ReminderResponseData[]>>;
}It reads client.reminders.paginator.state, and doesn't load a page by itself. The full entry is on Reminder hooks.
Lists without a hook
Read these lists with useStateStore and your own selector:
| List | Store |
|---|---|
| A channel list | paginator.state of the paginator you pass to ChannelList |
| The thread list | client.threads.paginator.state |
| A thread's replies | thread.messagePaginator.state |
| The channel details lists | searchSource.state of each list's context. See Channel details hooks. |