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

ThreadList

ThreadList lists the threads the current user takes part in. It reads client.threads, the thread manager, and renders a row for each thread in a React Native FlatList. Thread UI describes what it shows, and Replies and threads how the list loads and stays current.

Best practices

  • Render it anywhere inside Chat. It needs no Channel.
  • Pass the focus state of its screen as isFocused, such as useIsFocused() from React Navigation. The list keeps client.threads active only while it's true, so a hidden screen doesn't keep reloading the list.
  • Render one ThreadList at a time. Each one deactivates client.threads when it unmounts or loses focus, even while another list is still on screen.
  • Open the thread in onThreadSelect, for example by navigating to a screen that renders Thread with it. Without onThreadSelect, tapping a row does nothing.
  • Change the rows through the ThreadListItem override key, and keep them light: rows mount and unmount as the user scrolls.

Basic usage

src/ThreadsScreen.tsx
import { useIsFocused } from "@react-navigation/native";
import type { Thread } from "stream-chat";
import { ThreadList } from "stream-chat-react-native";

export const ThreadsScreen = ({
  openThread,
}: {
  openThread: (thread: Thread) => void;
}) => {
  const isFocused = useIsFocused();

  return <ThreadList isFocused={isFocused} onThreadSelect={openThread} />;
};

openThread gets the Thread instance of the row. Navigate with it, and render <Thread thread={thread}> on the thread's screen, as Moving between channels, threads and messages shows. The thread's channel is thread.channel.

ThreadList renders, from top to bottom:

  • ThreadListUnreadBanner, while threads outside the loaded list have new replies;
  • the rows, one for each thread in client.threads.paginator;
  • ThreadListLoadingMoreIndicator after the last row while the next page loads, or ThreadListEmptyPlaceholder, "Reply to a message to start a thread", when there are no threads;
  • a NotificationList for the list's notifications.

While the first page loads, it renders ThreadListLoadingIndicator, ten placeholder rows, instead of the banner and the rows. It loads the next page when the user scrolls to the end.

UI customization

ThreadList reads these keys from WithComponents. Thread UI shows a replacement row.

Override key Replaces Default Props
ThreadListComponent Everything above the notifications: the banner, the rows and the states DefaultThreadListComponent none; reads useThreadsContext()
ThreadListItem A row not exported none; reads useThreadListItemContext(). See ThreadListItem
ThreadListUnreadBanner The banner that reloads the list not exported none
ThreadListLoadingIndicator The placeholder rows while the first page loads DefaultThreadListLoadingIndicator none
ThreadListLoadingMoreIndicator The spinner after the last row DefaultThreadListLoadingNextIndicator none
ThreadListEmptyPlaceholder What shows when there are no threads DefaultThreadListEmptyPlaceholder none
NotificationList The notifications shown over the list NotificationList see NotificationList

The banner shows "2 new threads" while client.threads.state lists unseen threads, and tapping it reloads the list with client.threads.reload(). When the reload fails, it says so, and tapping it tries again.

Props

Prop Type Default Description
isFocused boolean true While true, client.threads is active: it loads the first page when the list has none, and reloads the list when threads got replies while it was inactive. false deactivates it. The type requires the prop, though the component treats a missing value as true.
onThreadSelect (thread: Thread) => void none Called with the row's thread when the user taps a row.
additionalFlatListProps Partial<FlatListProps<Thread>> none Props for the FlatList. They're spread after the SDK's own, so data, renderItem, onEndReached and ListEmptyComponent replace the SDK's.
notificationHostId string "thread-list:" and a random id The notification host the list's notifications are routed to. Pass one to publish notifications to this list from elsewhere.

When the list unmounts, it deactivates client.threads.

ThreadsContext

ThreadList provides ThreadsContext to everything it renders. useThreadsContext() reads it, and throws outside a ThreadList.

Value Type Description
threads Thread[] The threads of client.threads.paginator, in the list's order.
isLoading boolean Whether the first page is loading: the paginator is loading and has no threads.
isLoadingNext boolean Whether the next page is loading: the paginator is loading and has threads.
loadMore () => Promise<void> Loads the next page with client.threads.paginator.toTail(). Does nothing while a page loads or at the end.
onThreadSelect (thread: Thread) => void The ThreadList prop. The default row calls it when tapped.
isFocused boolean The ThreadList prop, as passed.
additionalFlatListProps Partial<FlatListProps<Thread>> The ThreadList prop. The default list spreads it onto its FlatList.

ThreadsContext, ThreadsProvider and the ThreadsContextValue type are exported. A ThreadListComponent of your own reads the threads and the loading states from it:

src/CompactThreadList.tsx
import { FlatList, Pressable, Text } from "react-native";
import type { Thread } from "stream-chat";
import { useThreadsContext } from "stream-chat-react-native";

const keyExtractor = (thread: Thread) => thread.id;

export const CompactThreadList = () => {
  const { isLoading, loadMore, onThreadSelect, threads } = useThreadsContext();

  if (isLoading) return <Text>Loading threads...</Text>;

  return (
    <FlatList
      data={threads}
      keyExtractor={keyExtractor}
      onEndReached={loadMore}
      renderItem={({ item }) => (
        <Pressable onPress={() => onThreadSelect?.(item)}>
          <Text numberOfLines={1}>{item.id}</Text>
        </Pressable>
      )}
    />
  );
};

Register it as ThreadListComponent. It replaces the banner too, so render ThreadListUnreadBanner from useComponentsContext() to keep it. A row of your own reads the thread's state with useStateStore(thread.state, selector); see Thread and thread manager.

Hook Returns
useThreadsContext() the values above; throws outside a ThreadList
useThreadListItemContext() the thread of the row being rendered, and the values the row shows
useStateStore() a selection of client.threads.state, client.threads.paginator.state or thread.state

client.threads.state holds unreadThreadCount and unseenThreadIds, and client.threads.paginator.state the threads, isLoading and lastQueryError. See useThreadsContext and Thread and thread manager.