ComponentsContext
ComponentsContext holds the override keys: for each replaceable part of the UI, the component the SDK renders there. Set keys with WithComponents, and read them with useComponentsContext(). Overriding components explains how overrides apply, and lists every key by area of the screen. This page covers the provider, the hook and their types.
Best practices
- Declare the
overridesobject once, at module scope, with its components declared at module scope too.WithComponentsreads it once, when it mounts. - Put
WithComponentsabove the component that reads the key.OverlayProviderreads the image gallery's keys,MessageOverlayBackgroundandMessageActions, andChatreadsChatLoadingIndicator, so those keys work only from aWithComponentsaround them. See Where to put WithComponents. - Read a key with
useComponentsContext()in a component of your own, rather than importing the SDK's default, so it shows the override the app registered. - A custom message component receives no props. It reads the message with
useMessageContext(). See A custom MessageItemView.
Basic usage
import type { PropsWithChildren } from "react";
import { Text } from "react-native";
import { WithComponents } from "stream-chat-react-native";
import type {
ComponentOverrides,
EmptyStateProps,
} from "stream-chat-react-native";
const EmptyState = ({ listType }: EmptyStateProps) => (
<Text>
{listType === "channel" ? "No conversations yet" : "Nothing here yet"}
</Text>
);
// Declared once, at module scope.
const overrides: ComponentOverrides = { EmptyStateIndicator: EmptyState };
export const AppOverrides = ({ children }: PropsWithChildren) => (
<WithComponents overrides={overrides}>{children}</WithComponents>
);A component of your own renders the same part through the context, so it shows EmptyState inside AppOverrides and the SDK's default elsewhere:
import { useComponentsContext } from "stream-chat-react-native";
export const NoResults = () => {
const { EmptyStateIndicator } = useComponentsContext();
return <EmptyStateIndicator listType="default" />;
};WithComponents
| Prop | Type | Default | Description |
|---|---|---|---|
overrides |
ComponentOverrides |
required | The keys to set for everything below. They replace the same keys from a WithComponents above, and the other keys keep their outer value. icons merges icon by icon. Read once, when it mounts. |
WithComponents also renders its children. No provider removes the overrides from above; to give a part of the app the SDK's component back, set the key to the default component again.
useComponentsContext
useComponentsContext() returns a ResolvedComponents object: every key, with the overrides in effect merged over the SDK's defaults, and icons merged icon by icon. It never throws. Outside every WithComponents, it returns the defaults.
The object is built once for each component that calls the hook, when it mounts. An override registered later reaches the component only when it mounts again.
Types
| Type | What it is |
|---|---|
ComponentOverrides |
The type of overrides. Every key is optional. It has 187 keys: 172 that have a default component, 14 optional slots that have none, and icons, a partial map of icon components. |
ResolvedComponents |
The type useComponentsContext() returns. It types every key as defined, and icons as the full map. |
ResolvedComponents also types the 14 optional slots as defined, but they're undefined at runtime until you set them. Check one before rendering it, for example MessageText ? <MessageText {...props} /> : null.
The keys in the type that no component reads, and so change nothing, are listed in Keys that change nothing.
Related hooks
useComponentsContext()returns the merged keys, as above.useMessageContext()gives a custom message component its message. See MessageContext.useTheme()gives a custom component the theme, so it matches the SDK's. See Theming.