<Chat client={chatClient} i18nInstance={streami18n}>
<Channel channel={channel} thread={thread}>
<MessageList onThreadSelect={setThread} />
<MessageInput />
</Channel>
</Chat>
Troubleshooting
There are a few common problems users have reported when setting up Stream Chat for React Native, to help you if you run afoul of these problems we have created a list of common issues and solutions. If you encounter something that is not listed here, try searching for the issue in GitHub.
Cannot run remote debugger
React Native is undergoing major architecture changes, Reanimated 2 has capitalized on the already released improvements and taken advantage of the JSI to provide an amazingly powerful library. Currently though there are a list of limitations that Reanimated 2 has, one of which is that the use of the JSI prevents debugging without using Flipper, therefore you must use Flipper for remote debugging.
Messages sending in thread instead of channel
There is an internal thread state that is used to track the current thread.
When you click on a thread and take an action such as navigating to another screen the thread
is set within the Channel
component in the current screen to the selected thread
.
When you return to the original screen you need to reset the thread to ensure it is not being set on the messages when they are sent.
We suggest you keep track of a thread
state on your own and provide it to any Channel
component you use whether on a channel or thread.
<Chat client={chatClient} i18nInstance={streami18n}>
<Channel channel={channel} thread={thread} threadList>
<Thread onThreadDismount={() => setThread(null)} />
</Channel>
</Chat>
You may be wondering why this is all necessary, this is because in most cases there is only a single OverlayProvider
.
The OverlayProvider
keeps track of the currently selected images in the image picker, and the images available to view in the image gallery from a given channel or thread.
To keep these in sync with the currently visible screen some logic is used to determine whether or not they should update, this logic is dependant on the thread
state.
Undefined is not a function
Stream Chat for React Native relies heavily on context, in instances where the Render Error undefined is not a function
occurs it is almost always the case that a context provider is not wrapping a component appropriately.
If you encounter this error please ensure the OverlayProvider
, Chat
, and Channel
components are wrapping your application correctly.
Incorrect input position
If the MessageInput
is at the incorrect height when the keyboard is displayed a setting could being incorrect.
Ensure the keyboardVerticalOffset
prop passed to Channel
is correct and accounts for any header height that may need to be adjusted for.
Android
On Android if the StatusBar is set to translucent, that is StatusBar.setTranslucent(true)
, there may be some inaccurate layout calculations occurring.
If you are using the standard React Native Android keyboard setting of android:windowSoftInputMode="adjustResize"
, you can disable to layout adjustments on Android using the prop disableKeyboardCompatibleView
and this will ignore the incorrect measurements.
Wrong images in gallery
The image viewer is created in the OverlayProvider
so it can cover the entire screen, thus if you are wrapping your navigation in the OverlayProvider
there is only copy present throughout the application.
The images present in the viewer are determined by logic based off of both the current channel
and thread
provided to the Channel
component.
You therefore must keep these props up to date as you navigate to ensure when returning to a channel from a thread the images in the viewer are once again updated to those from the channel.
To do this make sure your Channel
components are always aware of the thread state, even when being used for a channel.
<Channel channel={channel} thread={thread}>
<MessageList onThreadSelect={setThread} />
<MessageInput />
</Channel>
<Channel channel={channel} thread={thread} threadList>
<Thread onThreadDismount={() => setThread(null)} />
</Channel>
Image gallery not full screen
If the image viewer or message overlay is not covering the full screen, for instance it is rendering below or behind a Header, it is likely the OverlayProvider
is not setup in the correct location within the application.
Please refer to the Stream Chat with Navigation documentation to properly place the OverlayProvider
in relation to your navigation solution or other components.
Image picker incorrect height
The image picker opens the gallery to a height based on the location of the MessageInput
, if there is space below the MessageInput
, for instance a Safe Area or a Tab Bar, this must be taken into account.
To account for this the prop bottomInset
can be provided to the OverlayProvider
.
<OverlayProvider bottomInset={/** number */}>
{/* Inner component */}
</OverlayProvider>
Similarly if the gallery fully open is not at the desired height, this can be adjusted using the OverlayProvider
prop topInset
.
<OverlayProvider topInset={/** number */}>
{/* Inner component */}
</OverlayProvider>
topInset
prior to version 3.6.0
needed to be set before the image picker would render.
Additionally it could only be set one time via either props or the setTopInset
function, otherwise the gallery would open to incorrect heights.
Both bottomInset
& topInset
can be set via the appropriate functions, setBottomInset
and setTopInset
, that are accessible via the useAttachmentPickerContext
hook.
Android
On Android if the StatusBar is set to translucent, that is StatusBar.setTranslucent(true)
, you should add the height adjustments using the setTopInset
function of the useAttachmentPickerContext
hook.
import { StatusBar } from "react-native";
import { useHeaderHeight } from "@react-navigation/elements";
import { useAttachmentPickerContext } from "stream-chat-react-native";
const headerHeight = useHeaderHeight();
const { setTopInset } = useAttachmentPickerContext();
// When the status bar is translucent, the headerHeight contains the actual header height + the status bar height which needs to be substracted.
const finalHeaderHeight =
headerHeight -
(Platform.OS === "android" && StatusBar.currentHeight
? StatusBar.currentHeight
: 0);
useEffect(() => {
setTopInset(finalHeaderHeight);
}, [setTopInset, finalHeaderHeight]);
This can also be passed to the topInset
prop of OverlayProvider
.
It is important to note that since Expo 38 true
is the default for transparent on Android.
Image picker not working
If the image picker is appearing incorrectly, for instance behind a bottom Tab Bar, it is likely the OverlayProvider
is not setup in the correct location within the application.
Please refer to the Stream Chat with Navigation documentation to properly place the OverlayProvider
in relation to your navigation solution.
iOS
Add the NSPhotoLibraryUsageDescription
key in your Info.plist
with a description of use.
Add the NSPhotoLibraryAddUsageDescription
key in your Info.plist
with a description of use.
Android
The following permissions are required for the image picker to work on Android, and must be included in the AndroidManifest.xml
file.
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
If your Android app is using targetSdkVersion of 33 or above. We expect that you are using React Native version 0.71 or above to ask for the media permissions instead of storage permissions. Please ensure that your app has this combination.
Camera not working
iOS
Add the NSCameraUsageDescription
key in your Info.plist
with a description of use.
Add the NSPhotoLibraryUsageDescription
key in your Info.plist
with a description of use.
Add the NSMicrophoneUsageDescription
key in your Info.plist
with a description of use.
Android
The standard camera permissions are required for the camera to work on Android, and must be included in the AndroidManifest.xml
file.
<uses-permission android:name="android.permission.CAMERA"/>
Add maven { url 'https://maven.google.com' }
to android/build.gradle
allprojects {
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
google()
maven { url 'https://maven.google.com' }
maven { url 'https://www.jitpack.io' }
}
}
Ensure buildToolsVersion
, compileSdkVersion
, and targetSdkVersion
are all >= 26 in android/build.gradle
buildscript {
ext {
buildToolsVersion = "29.0.3"
compileSdkVersion = 29
targetSdkVersion = 29
...
}
...
}
Add vectorDrawables.useSupportLibrary = true
to android/app/build.gradle
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
...
}
...
}
External Link not opening
Android
Opening an external link doesn’t work without permissions on targetSdkVersion
>= 30. So, the following permission must be included in the AndroidManifest.xml
file.
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" android:host="*" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" android:host="*" />
</intent>
</queries>
GIF and WebP not displaying
Android
GIF and WebP do not work without additional modules by default on Android.
You will need to add some modules in your android/app/build.gradle
dependencies {
// For animated GIF support
implementation 'com.facebook.fresco:animated-gif:2.6.0'
// For WebP support, including animated WebP
implementation 'com.facebook.fresco:animated-webp:2.6.0'
implementation 'com.facebook.fresco:webpsupport:2.6.0'
// Provide the Android support library (you might already have this or a similar dependency)
implementation 'com.android.support:support-core-utils:24.2.1'
...
}
Blank screen when channel gets delete
When a channel is deleted, and if some user is active on that channel, a blank screen appears by default (as per the default logic) as we return null
in this case.
It might be confusing for end user to see a blank screen and appropriate UX would be to navigate back to channel list screen.
You can implement such UX by listening to channel.deleted
event on channel screen, and navigate to channel list screen with appropriate notification on app.
client.on("channel.deleted", (event) => {
if (event.cid === channel.cid) {
// add your action here
}
});
Touchables
not working
If you are having trouble with pressing, swiping, or otherwise interacting with components it is likely the result of React Native Gesture Handler not being properly setup.
If your React Native version is (>=0.68) you will need a version of >=2.0.0 for react-native-gesture-handler
for your app to build.
Be sure to follow all needed additional steps to complete the installation.
This includes ensuring you import react-native-gesture-handler
at the top of your app entry file.
import "react-native-gesture-handler";
Also do not forget to wrap your component tree(probably above OverlayProvider
) with <GestureHandlerRootView>
or gestureHandlerRootHOC
as mentioned in RNGH Installation docs. Not doing so, can cause unusual behaviour with the MessageOverlay
and Imagegallery
gestures.
<GestureHandlerRootView style={{ flex: 1 }}>
<OverlayProvider>{/* Other underlying components */}</OverlayProvider>
</GestureHandlerRootView>
If you are using v1 of react-native-gesture-handler
library, then you will need extra setup steps for Android.
Update MainActivity.java
to override the method for creating the ReactRootView
as mentioned in RNGH Installation docs.
package com.swmansion.gesturehandler.react.example;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "Example";
}
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
@Override
protected ReactRootView createRootView() {
return new RNGestureHandlerEnabledRootView(MainActivity.this);
}
};
}
}
Touchables
Inside Custom Components Are Not Working
If you find that a customization that includes a touchable is not working, or the wrong element is receiving the touch event, this is likely related to React Native Gesture Handler. The following could be the reasons behind the issues you might be facing:
- Your component may be being rendered inside of a gesture handler.
- Nested gesture handlers and
touchables
need special treatment and can act differently on iOS & Android. If you want NestedTouchables
to work on Android you should add the propdisallowInterruption
as mentioned here.
There are solutions available for almost all use cases so looking into your specific use case in relation to React Native Gesture Handler is suggested. The solution may require using a different touchable from React Native Gesture Handler and React Native depending on the platform.
Reanimated 2
We rely on Reanimated 2 heavily for gesture based interactions and animations. It is vital you follow the Reanimated 2 installation instructions for the library to work properly.
Failed to create a Worklet
If you are encountering errors related to Reanimated 2 failed to create a worklet
you must likely forgot to add the react-native-reanimated/plugin
to your project’s babel config file. Below is an example of adding Reanimated babel plugin to babel.config.js
:
module.exports = {
...
plugins: [
...
'react-native-reanimated/plugin',
],
};
Reanimated plugin has to be listed last.
Blank screen on Android
This step is only required for older version of (Reanimated 2). If you are using version >=3.0.0, you can skip this step.
If you are encountering errors on Android and the screen is blank it is likely you forgot to finish the Reanimated 2 Android setup.
Ensure Hermes is enabled in android/app/build.gradle
:
project.ext.react = [
enableHermes: true // clean and rebuild if changing
]
Add Reanimated in MainApplication.java
import com.facebook.react.bridge.JSIModulePackage;
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
...
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
...
@Override
protected String getJSMainModuleName() {
return "index";
}
@Override
protected JSIModulePackage getJSIModulePackage() {
return new ReanimatedJSIModulePackage();
}
};
...
Android release bundle is crashing
This is likely due to ProGuard removing reanimated 2 related classes. If you’re using ProGuard, make sure to add the rules below:
-keep class com.swmansion.reanimated.** { *; }
-keep class com.facebook.react.turbomodule.** { *; }
Project won’t build on a MacBook with Apple M1
On newer MacBooks with the Apple M1 SoC, there are a few required steps that need to be followed for an app to build. The user aiba has written a guide to make the necessary changes to your project.
The iOS build version can be changed to suit your needs, but keep in mind to change the version to the same major and minor version consistently throughout the guide.
React Native Video failing with Xcode 17
Following error is a known issue with using Xcode 17 and react-native-video dependency.
The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
To temporarily fix this, you can follow the solution as per mentioned in the description of this issue on GitHub.
Alternatively, you can apply this patch using the patch-package library to the package react-native-video
.
This shall be fixed soon with the new alpha release of the package react-native-video
.
- Cannot run remote debugger
- Messages sending in thread instead of channel
- Undefined is not a function
- Incorrect input position
- Wrong images in gallery
- Image gallery not full screen
- Image picker incorrect height
- Image picker not working
- Camera not working
- External Link not opening
- GIF and WebP not displaying
- Blank screen when channel gets delete
- Touchables not working
- Touchables Inside Custom Components Are Not Working
- Reanimated 2
- Project won’t build on a MacBook with Apple M1
- React Native Video failing with Xcode 17