GetStream / stream-chat-react-native

💬 React-Native Chat SDK ➜ Stream Chat. Includes a tutorial on building your own chat app experience using React-Native, React-Navigation and Stream
https://getstream.io/chat/sdk/react-native/
Other
961 stars 323 forks source link

Best Practices for Integrating Stream Chat SDK in a Large Application: Questions on useChannelContext and Error Handling #2497

Closed david-shiko closed 5 months ago

david-shiko commented 5 months ago

Hello Stream Team,

I am currently integrating Stream Chat into a large-scale application and aiming to implement chat functionality using standard methods provided by your SDK. However, I've encountered several issues and have some questions to ensure that I am using your tools correctly:

General Integration Logic

Usage of useChannelContext and Custom Providers

Error Understanding

Additional Questions

Types for GetStreamStackParamList

Direct Import of Types from dist

Filters in ChannelList

Ensuring Complete Integration

I appreciate any guidance or resources you can provide to help clarify these points.

Thank you!

// MessengerScreen.tsx
import React from 'react';
import { ChannelList } from 'stream-chat-expo';
import { useNavigation } from '@react-navigation/native';

export default function Messenger(): React.ReactElement {

    const navigation = useNavigation();

    return (
        <ChannelList 
        filters={{ members: { $in: ['steve'] } }}
        onSelect={(channel) => {
            navigation.navigate('Channel')
        }}
    );
}

// ChannelScreen.tsx
import { useChannelContext } from 'stream-chat-expo';

const ChannelScreen = () => {
    const { channel } = useChannelContext(); // Not works. useGetStreamChatContext does works

    return (
        <Channel channel={channel}>
            <MessageList />
            <MessageInput />
        </Channel>
    );
};

export default ChannelScreen;

// Navigation.ts
import { Chat, OverlayProvider } from 'stream-chat-expo';
import {createStackNavigator} from '@react-navigation/stack';
import { useUserContext } from 'app/src/contexts/User';
import { MessengerScreen, ChannelScreen } from 'app/screens';

export type GetStreamStackParamList = {
    Messenger: any; // TODO Need types
    Channel: any; // TODO Need types
};

const GetStreamStack = createStackNavigator<GetStreamStackParamList>();

export function GetStreamStackScreen(): React.ReactElement {

    const { user } = useUserContext();
    user.messenger.connectUser() // TODO use hook
    return (
        <OverlayProvider>
            <Chat client={user.messenger.provider.client}>
                <GetStreamStack.Navigator initialRouteName='Messenger'>
                    <GetStreamStack.Screen name='Messenger' component={MessengerScreen}/>
                    <GetStreamStack.Screen name='Channel' component={ChannelScreen}/>
                </GetStreamStack.Navigator>
            </Chat>
        </OverlayProvider>
    );
}

// App.tsx
import React from 'react';
import registerRootComponent from 'expo/build/launch/registerRootComponent';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import AppNavigator from 'app/src/navigation/AppNavigator';

export default function App() {
    return (
        <GestureHandlerRootView style={{ flex: 1 }}>
            <GetStreamChatProvider>
                <AppNavigator />
            </GetStreamChatProvider>
        </GestureHandlerRootView>
    );
}

registerRootComponent(App);

/*
    WITH THIS CUSTOM PROVIDER THE APP WORKS
*/
import React, { createContext, useState, useContext } from 'react';
import type { Channel  as ChannelType, Thread as ThreadType } from 'stream-chat/dist/types'

type GetStreamChatContextType = {
  channel: ChannelType | null;
  setChannel: (channel: ChannelType | null) => void;
  thread: ThreadType | null;
  setThread: (thread: ThreadType | null) => void;
}

export const getStreamChatContext = createContext<GetStreamChatContextType>({
  channel: null,
  setChannel: (channel) => {},
  thread: null,
  setThread: (thread) => {},
});

export function GetStreamChatProvider({ children }) {
  const [channel, setChannel] = useState<ChannelType | null>(null);
  const [thread, setThread] = useState<ThreadType | null>(null);

  return (
    <getStreamChatContext.Provider value={{ channel, setChannel, thread, setThread }}>
      {children}
    </getStreamChatContext.Provider>
  );
};

export { ChannelType, ThreadType };
export const useGetStreamChatContext = () => useContext(getStreamChatContext);

Enviroment:

{
  "name": "rubiklovemobile",
  "version": "1.0.0",
  "main": "app/src/App.tsx",
  "scripts": {
    "start": "expo start",
    "android": "expo run:android",
    "ios": "expo run:ios",
    "web": "expo start --web",
    "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
    "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix"
  },
  "dependencies": {
    "@expo/metro-config": "~0.17.1",
    "@expo/webpack-config": "~19.0.1",
    "@ptomasroos/react-native-multi-slider": "^2.2.2",
    "@react-native-community/netinfo": "11.1.0",
    "@react-native-google-signin/google-signin": "^11.0.0",
    "@react-native-picker/picker": "2.6.1",
    "@react-navigation/bottom-tabs": "^6.5.7",
    "@react-navigation/native": "^6.1.6",
    "@react-navigation/stack": "^6.3.16",
    "@stream-io/flat-list-mvcp": "^0.10.3",
    "axios": "^1.3.4",
    "expo": "~50.0.17",
    "expo-auth-session": "~5.4.0",
    "expo-crypto": "~12.8.1",
    "expo-file-system": "~16.0.9",
    "expo-image-manipulator": "~11.8.0",
    "expo-image-picker": "~14.7.1",
    "expo-linear-gradient": "~12.7.2",
    "expo-location": "~16.5.5",
    "expo-media-library": "~15.9.2",
    "expo-splash-screen": "~0.26.4",
    "expo-status-bar": "~1.11.1",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-native": "0.73.6",
    "react-native-auth0": "^3.1.0",
    "react-native-gesture-handler": "~2.14.0",
    "react-native-image-picker": "^7.1.0",
    "react-native-maps": "1.10.0",
    "react-native-pager-view": "6.2.3",
    "react-native-reanimated": "~3.6.2",
    "react-native-safe-area-context": "4.8.2",
    "react-native-svg": "14.1.0",
    "react-native-tab-view": "^3.5.1",
    "react-native-textinput-effects": "^0.6.3",
    "react-native-walkthrough-tooltip": "^1.5.0",
    "react-native-web": "~0.19.6",
    "stream-chat-expo": "^5.27.1"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@types/react": "~18.2.45",
    "@types/react-native": "^0.73.0",
    "@typescript-eslint/eslint-plugin": ">=5.43.0",
    "@typescript-eslint/parser": ">=5.43.0",
    "babel-plugin-module-resolver": "^5.0.0",
    "dependency-cruiser": "^16.2.0",
    "eslint": "8",
    "eslint-config-standard-with-typescript": "^43.0.1",
    "eslint-config-xo": "^0.44.0",
    "eslint-config-xo-typescript": "^2.0.0",
    "eslint-plugin-import": "^2.25.2",
    "eslint-plugin-n": "^16.6.2",
    "eslint-plugin-promise": "^6.0.0",
    "eslint-plugin-react": "^7.32.2",
    "madge": "^6.0.0",
    "react-native-screens": "~3.29.0",
    "react-native-svg-transformer": "^1.0.0",
    "typescript": "^5.3.0"
  },
  "private": true
}

Device:

adb -s emulator-5554 shell getprop ro.build.version.sdk
31
adb -s emulator-5554 shell getprop ro.product.brand
google
adb -s emulator-5554 shell getprop ro.product.model
sdk_gphone64_x86_64
adb -s emulator-5554 shell getprop ro.build.version.release
12

Running:

npx expo start -c -> a

gc0rtes commented 5 months ago

Hey @david-shiko, thank you for reaching out.

The issue section of the repository is reserved for reporting bugs and vulnerabilities related to the RN SDK. For implementation assistance, please direct your questions to the Stream support team by submitting a ticket here: https://getstream.io/contact/support/

Looking forward to hearing from you.

Best regards, Guilherme Integration Support Engineer

david-shiko commented 5 months ago

Hi! Thanks for the answer! By the way, I have an issue related to the React Native (RN) SDK, specifically with the GetStream chat screens (Chat, Channel List, Channel) which overlap my bottom menu from the React Native Navigation library. I'm not very experienced with layout design, but I think it's related to the OverlayProvider. According to the documentation, it should be positioned outside of the navigation components (stack screen). However, instead of wrapping the screens as usual, my bottom menu is now inside the GetStream Chat wrapper and is being overlapped by it. I could manually add padding to make my bottom menu visible, but the real problem, in my opinion, is that wrapping the navigation is breaking the design architecture. I'm sorry that I can't provide the code right now, but maybe you will kindly grasp the essence without the code? :l