diff --git a/docusaurus/docs/reactnative/core-components/chat.mdx b/docusaurus/docs/reactnative/core-components/chat.mdx
index 59cf435ab5..2b71afb5cf 100644
--- a/docusaurus/docs/reactnative/core-components/chat.mdx
+++ b/docusaurus/docs/reactnative/core-components/chat.mdx
@@ -23,21 +23,45 @@ We recommend using only one instance of `Chat` provider per application unless a
```tsx
import { StreamChat } from 'stream-chat';
-import { ChannelList, Chat, OverlayProvider } from 'stream-chat-react-native';
-
-const client = StreamChat.getInstance('api_key');
-
-export const App = () => (
-
- // highlight-next-line
-
-
+import { ChannelList, Chat, OverlayProvider, useCreateChatClient } from 'stream-chat-react-native';
+
+// highlight-start
+const chatApiKey = 'REPLACE_WITH_API_KEY';
+const chatUserId = 'REPLACE_WITH_USER_ID';
+const chatUserName = 'REPLACE_WITH_USER_NAME';
+const chatUserToken = 'REPLACE_WITH_USER_TOKEN';
+// highlight-end
+
+const user = {
+ id: chatUserId,
+ name: chatUserName,
+};
+
+export const App = () => {
+ // highlight-start
+ const chatClient = useCreateChatClient({
+ apiKey: chatApiKey,
+ userData: user,
+ tokenOrProvider: chatUserToken,
+ });
+ // highlight-end
+
+ return (
+
// highlight-next-line
-
-
-);
+
+
+ // highlight-next-line
+
+
+ );
+};
```
+:::tip
+You can use the `useCreateChatClient` hook from `stream-chat-react-native`/`stream-chat-expo` to create a client instance and automatically connect/disconnect a user as per the example above, for simplicity.
+:::
+
## Context Providers
`Chat` contains providers for the `ChatContext`, `ThemeContext`, and `TranslationContext`.
diff --git a/docusaurus/docs/reactnative/ui-components/overview.mdx b/docusaurus/docs/reactnative/ui-components/overview.mdx
index 29886c4d33..7105b63d4b 100644
--- a/docusaurus/docs/reactnative/ui-components/overview.mdx
+++ b/docusaurus/docs/reactnative/ui-components/overview.mdx
@@ -67,6 +67,10 @@ To disconnect a user you can call `disconnectUser` on the client.
await client.disconnectUser();
```
+:::tip
+Alternatively, you can also use the `useCreateChatClient` hook from `stream-chat-react-native`/`stream-chat-expo` to create a client instance and automatically connect/disconnect a user.
+:::
+
## Creating a Channel
Channels are at the core of Stream Chat, they are where messages are contained, sent, and interacted with.
diff --git a/examples/ExpoMessaging/components/ChatWrapper.tsx b/examples/ExpoMessaging/components/ChatWrapper.tsx
index 831fbb63f4..2b94215ffd 100644
--- a/examples/ExpoMessaging/components/ChatWrapper.tsx
+++ b/examples/ExpoMessaging/components/ChatWrapper.tsx
@@ -1,6 +1,5 @@
import React, { PropsWithChildren } from 'react';
-import { Chat, OverlayProvider, Streami18n } from 'stream-chat-expo';
-import { useChatClient } from '../hooks/useChatClient';
+import { Chat, OverlayProvider, Streami18n, useCreateChatClient } from 'stream-chat-expo';
import { AuthProgressLoader } from './AuthProgressLoader';
import { StreamChatGenerics } from '../types';
import { STREAM_API_KEY, user, userToken } from '../constants';
@@ -12,7 +11,7 @@ const streami18n = new Streami18n({
export const ChatWrapper = ({ children }: PropsWithChildren<{}>) => {
const { bottom } = useSafeAreaInsets();
- const chatClient = useChatClient({
+ const chatClient = useCreateChatClient({
apiKey: STREAM_API_KEY,
userData: user,
tokenOrProvider: userToken,
@@ -24,7 +23,7 @@ export const ChatWrapper = ({ children }: PropsWithChildren<{}>) => {
return (
bottomInset={bottom} i18nInstance={streami18n}>
-
+
{children}
diff --git a/examples/ExpoMessaging/hooks/useChatClient.tsx b/examples/ExpoMessaging/hooks/useChatClient.tsx
deleted file mode 100644
index 73408bff0d..0000000000
--- a/examples/ExpoMessaging/hooks/useChatClient.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import {useEffect, useState} from 'react';
-import {StreamChat, OwnUserResponse, UserResponse} from 'stream-chat';
-import {StreamChatGenerics} from '../types';
-
-export const useChatClient = <
- SCG extends StreamChatGenerics = StreamChatGenerics,
->({
- apiKey,
- userData,
- tokenOrProvider,
-}: {
- apiKey: string;
- userData?: OwnUserResponse | UserResponse;
- tokenOrProvider?: string;
-}) => {
- const [chatClient, setChatClient] = useState | null>(null);
-
- useEffect(() => {
- const client = new StreamChat(apiKey);
-
- if (!userData) {
- return;
- }
-
- let didUserConnectInterrupt = false;
- let connectionPromise = client
- .connectUser(userData, tokenOrProvider)
- .then(() => {
- if (!didUserConnectInterrupt) {
- setChatClient(client);
- }
- });
-
- return () => {
- didUserConnectInterrupt = true;
- setChatClient(null);
- connectionPromise
- .then(() => client.disconnectUser())
- .then(() => {
- console.log('Connection closed');
- });
- };
- }, [apiKey, userData, tokenOrProvider]);
-
- return chatClient;
-};
diff --git a/examples/TypeScriptMessaging/App.tsx b/examples/TypeScriptMessaging/App.tsx
index 16859bd69f..44bd02155a 100644
--- a/examples/TypeScriptMessaging/App.tsx
+++ b/examples/TypeScriptMessaging/App.tsx
@@ -4,7 +4,7 @@ import { DarkTheme, DefaultTheme, NavigationContainer, RouteProp } from '@react-
import { createStackNavigator, StackNavigationProp } from '@react-navigation/stack';
import { useHeaderHeight } from '@react-navigation/elements';
import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context';
-import { Channel as ChannelType, ChannelSort, StreamChat } from 'stream-chat';
+import { Channel as ChannelType, ChannelSort } from 'stream-chat';
import {
Channel,
ChannelList,
@@ -18,12 +18,14 @@ import {
Thread,
ThreadContextValue,
useAttachmentPickerContext,
+ useCreateChatClient,
useOverlayContext,
} from 'stream-chat-react-native';
import { useStreamChatTheme } from './useStreamChatTheme';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { useFlipper } from 'stream-chat-react-native-devtools';
+import { AuthProgressLoader } from './AuthProgressLoader';
LogBox.ignoreAllLogs(true);
@@ -62,7 +64,7 @@ QuickSqliteClient.logger = (level, message, extraData) => {
console.log(level, `QuickSqliteClient: ${message}`, extraData);
};
-const chatClient = StreamChat.getInstance('q95x9hkbyd6p');
+const apiKey = 'q95x9hkbyd6p';
const userToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoicm9uIn0.eRVjxLvd4aqCEHY_JRa97g6k7WpHEhxL7Z4K4yTot1c';
@@ -219,85 +221,82 @@ type AppContextType = {
const AppContext = React.createContext({} as AppContextType);
const App = () => {
- const colorScheme = useColorScheme();
const { bottom } = useSafeAreaInsets();
const theme = useStreamChatTheme();
+ const { channel } = useContext(AppContext);
- const [channel, setChannel] = useState>();
- const [clientReady, setClientReady] = useState(false);
- const [thread, setThread] = useState['thread']>();
-
- useEffect(() => {
- const setupClient = async () => {
- const connectPromise = chatClient.connectUser(user, userToken);
- setClientReady(true);
- await connectPromise;
- };
+ const chatClient = useCreateChatClient({
+ apiKey,
+ userData: user,
+ tokenOrProvider: userToken,
+ });
- setupClient();
- }, []);
+ if (!chatClient) {
+ return ;
+ }
return (
-
-
-
-
-
- bottomInset={bottom}
- i18nInstance={streami18n}
- value={{ style: theme }}
- >
-
- {clientReady && (
-
- ({
- headerBackTitle: 'Back',
- headerRight: EmptyHeader,
- headerTitle: channel?.data?.name,
- })}
- />
-
- ({ headerLeft: EmptyHeader })}
- />
-
- )}
-
-
-
-
-
-
+
+ bottomInset={bottom}
+ i18nInstance={streami18n}
+ value={{ style: theme }}
+ >
+
+
+ ({
+ headerBackTitle: 'Back',
+ headerRight: EmptyHeader,
+ headerTitle: channel?.data?.name,
+ })}
+ />
+
+ ({ headerLeft: EmptyHeader })}
+ />
+
+
+
);
};
export default () => {
+ const [channel, setChannel] = useState>();
+ const [thread, setThread] = useState['thread']>();
const theme = useStreamChatTheme();
+ const colorScheme = useColorScheme();
return (
-
+
+
+
+
+
+
+
+
+
);
};
diff --git a/examples/TypeScriptMessaging/AuthProgressLoader.tsx b/examples/TypeScriptMessaging/AuthProgressLoader.tsx
new file mode 100644
index 0000000000..a98d5d643a
--- /dev/null
+++ b/examples/TypeScriptMessaging/AuthProgressLoader.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { ActivityIndicator, StyleSheet } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+
+export const AuthProgressLoader = () => {
+ return (
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+});
diff --git a/package/src/components/Chat/hooks/useCreateChatClient.ts b/package/src/components/Chat/hooks/useCreateChatClient.ts
new file mode 100644
index 0000000000..f98af175a3
--- /dev/null
+++ b/package/src/components/Chat/hooks/useCreateChatClient.ts
@@ -0,0 +1,57 @@
+import { useEffect, useState } from 'react';
+
+import { StreamChat } from 'stream-chat';
+
+import type {
+ DefaultGenerics,
+ ExtendableGenerics,
+ OwnUserResponse,
+ StreamChatOptions,
+ TokenOrProvider,
+ UserResponse,
+} from 'stream-chat';
+
+/**
+ * React hook to create, connect and return `StreamChat` client.
+ */
+export const useCreateChatClient = ({
+ apiKey,
+ options,
+ tokenOrProvider,
+ userData,
+}: {
+ apiKey: string;
+ tokenOrProvider: TokenOrProvider;
+ userData: OwnUserResponse | UserResponse;
+ options?: StreamChatOptions;
+}) => {
+ const [chatClient, setChatClient] = useState | null>(null);
+ const [cachedUserData, setCachedUserData] = useState(userData);
+
+ if (userData.id !== cachedUserData.id) {
+ setCachedUserData(userData);
+ }
+
+ const [cachedOptions] = useState(options);
+
+ useEffect(() => {
+ const client = new StreamChat(apiKey, undefined, cachedOptions);
+ let didUserConnectInterrupt = false;
+
+ const connectionPromise = client.connectUser(cachedUserData, tokenOrProvider).then(() => {
+ if (!didUserConnectInterrupt) setChatClient(client);
+ });
+
+ return () => {
+ didUserConnectInterrupt = true;
+ setChatClient(null);
+ connectionPromise
+ .then(() => client.disconnectUser())
+ .then(() => {
+ console.log(`Connection for user "${cachedUserData.id}" has been closed`);
+ });
+ };
+ }, [apiKey, cachedUserData, cachedOptions, tokenOrProvider]);
+
+ return chatClient;
+};
diff --git a/package/src/components/index.ts b/package/src/components/index.ts
index 3a43e98a15..abeb80568e 100644
--- a/package/src/components/index.ts
+++ b/package/src/components/index.ts
@@ -69,6 +69,7 @@ export * from './ChannelPreview/hooks/useChannelPreviewDisplayPresence';
export * from './ChannelPreview/hooks/useLatestMessagePreview';
export * from './Chat/Chat';
+export * from './Chat/hooks/useCreateChatClient';
export * from './Chat/hooks/useCreateChatContext';
export * from './Chat/hooks/useIsOnline';
export * from './Chat/hooks/useMutedUsers';