@@ -3,6 +3,7 @@ import { Image, Platform } from 'react-native';
33
44import type { Channel , StreamChat } from 'stream-chat' ;
55
6+ import { LoadingIndicator as LoadingIndicatorDefault } from './components/LoadingIndicator' ;
67import { useAppSettings } from './hooks/useAppSettings' ;
78import { useCreateChatContext } from './hooks/useCreateChatContext' ;
89import { useIsOnline } from './hooks/useIsOnline' ;
@@ -137,11 +138,6 @@ export type ChatProps<
137138 style ?: DeepPartial < Theme > ;
138139 } ;
139140
140- const initialisedDatabaseConfig : {
141- initialised : boolean ;
142- userID ?: string ;
143- } = { initialised : false , userID : '' } ;
144-
145141const ChatWithContext = <
146142 StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics ,
147143> (
@@ -154,6 +150,7 @@ const ChatWithContext = <
154150 enableOfflineSupport = false ,
155151 i18nInstance,
156152 ImageComponent = Image ,
153+ LoadingIndicator = LoadingIndicatorDefault ,
157154 resizableCDNHosts = [ '.stream-io-cdn.com' ] ,
158155 style,
159156 } = props ;
@@ -162,7 +159,6 @@ const ChatWithContext = <
162159
163160 // Setup translators
164161 const translators = useStreami18n ( i18nInstance ) ;
165- const userID = client . userID ;
166162
167163 /**
168164 * Setup connection event listeners
@@ -172,6 +168,13 @@ const ChatWithContext = <
172168 closeConnectionOnBackground ,
173169 ) ;
174170
171+ const [ initialisedDatabaseConfig , setInitialisedDatabaseConfig ] = useState < {
172+ initialised : boolean ;
173+ userID ?: string ;
174+ } > ( {
175+ initialised : false ,
176+ } ) ;
177+
175178 /**
176179 * Setup muted user listener
177180 * TODO: reimplement
@@ -181,6 +184,8 @@ const ChatWithContext = <
181184 const debugRef = useDebugContext ( ) ;
182185 const isDebugModeEnabled = __DEV__ && debugRef && debugRef . current ;
183186
187+ const userID = client . userID ;
188+
184189 // Set the `resizableCDNHosts` as per the prop.
185190 StreamChatRN . setConfig ( { resizableCDNHosts } ) ;
186191
@@ -207,6 +212,12 @@ const ChatWithContext = <
207212
208213 useEffect ( ( ) => {
209214 if ( userID && enableOfflineSupport ) {
215+ // This acts as a lock for some very rare occurrences of concurrency
216+ // issues we've encountered before with the QuickSqliteClient being
217+ // uninitialized before it's being invoked.
218+ setInitialisedDatabaseConfig ( { initialised : false , userID } ) ;
219+ QuickSqliteClient . initializeDatabase ( ) ;
220+ setInitialisedDatabaseConfig ( { initialised : true , userID } ) ;
210221 DBSyncManager . init ( client as unknown as StreamChat ) ;
211222 }
212223 // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -228,18 +239,10 @@ const ChatWithContext = <
228239 // on unmount if it exists to prevent a memory leak.
229240 useEffect ( ( ) => ( ) => DBSyncManager . connectionChangedListener ?. unsubscribe ( ) , [ ] ) ;
230241
231- if ( enableOfflineSupport && ! initialisedDatabaseConfig . initialised ) {
232- QuickSqliteClient . initializeDatabase ( ) ;
233- initialisedDatabaseConfig . userID = userID ;
234- initialisedDatabaseConfig . initialised = true ;
235- }
236-
237- const appSettings = useAppSettings ( client , isOnline , enableOfflineSupport ) ;
242+ const initialisedDatabase =
243+ initialisedDatabaseConfig . initialised && userID === initialisedDatabaseConfig . userID ;
238244
239- useSyncDatabase ( {
240- client,
241- enableOfflineSupport,
242- } ) ;
245+ const appSettings = useAppSettings ( client , isOnline , enableOfflineSupport , initialisedDatabase ) ;
243246
244247 const chatContext = useCreateChatContext ( {
245248 appSettings,
@@ -254,6 +257,17 @@ const ChatWithContext = <
254257 setActiveChannel,
255258 } ) ;
256259
260+ useSyncDatabase ( {
261+ client,
262+ enableOfflineSupport,
263+ initialisedDatabase,
264+ } ) ;
265+
266+ if ( userID && enableOfflineSupport && ! initialisedDatabase ) {
267+ // if user id has been set and offline support is enabled, we need to wait for database to be initialised
268+ return LoadingIndicator ? < LoadingIndicator /> : null ;
269+ }
270+
257271 return (
258272 < ChatProvider < StreamChatGenerics > value = { chatContext } >
259273 < TranslationProvider
@@ -278,6 +292,15 @@ const ChatWithContext = <
278292 * - connectionRecovering - whether or not websocket is reconnecting
279293 * - isOnline - whether or not set user is active
280294 * - setActiveChannel - function to set the currently active channel
295+ *
296+ * The Chat Component takes the following generics in order:
297+ * - At (AttachmentType) - custom Attachment object extension
298+ * - Ct (ChannelType) - custom Channel object extension
299+ * - Co (CommandType) - custom Command string union extension
300+ * - Ev (EventType) - custom Event object extension
301+ * - Me (MessageType) - custom Message object extension
302+ * - Re (ReactionType) - custom Reaction object extension
303+ * - Us (UserType) - custom User object extension
281304 */
282305export const Chat = <
283306 StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics ,
0 commit comments