Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App crashes when sending message in Gifted Chat #2550

Open
altunf opened this issue Oct 22, 2024 · 8 comments
Open

App crashes when sending message in Gifted Chat #2550

altunf opened this issue Oct 22, 2024 · 8 comments

Comments

@altunf
Copy link

altunf commented Oct 22, 2024

App crashes when sending message in Gifted Chat

I am experiencing a crash in my Expo app when I send a message using the Gifted Chat component. The app works perfectly in the Android simulator but crashes when I build the APK and run it on a physical device.

Steps to reproduce:

  • Build the Expo app as a preview build (APK).
  • Install the APK on a physical Android device.
  • Open the app and navigate to the chat screen.
  • Type a message and press the send button.
  • The app crashes immediately.

Code Snippets

`
import React, { useState, useCallback, useEffect } from "react";
import { Bubble, GiftedChat, Send } from "react-native-gifted-chat";
import { SafeAreaView, View, Text } from "react-native";
import { Colors } from "../../constants/Colors";
import { Ionicons } from "@expo/vector-icons";
import { useSafeAreaInsets } from "react-native-safe-area-context";

const ChatScreen = () => {
  const insets = useSafeAreaInsets();
  const [messages, setMessages] = useState([]);
  const [isTyping, setIsTyping] = useState(false);
  const [text, setText] = useState("");

useEffect(() => {
  test();
}, []);

const test = async (userMessage) => {
  setIsTyping(true);
  try {
    const newMessage = {
      _id: Date.now(),
      text: "random msg",
      createdAt: new Date(),
      user: { _id: 2, name: "AI Assistant" },
      isStarred: false,
    };
    setMessages((prev) => GiftedChat.append(prev, [newMessage]));
  } catch (error) {
    console.error("API Error:", error);
  } finally {
    setIsTyping(false);
  }
};

const onSend = useCallback(async (messages = []) => {
  setMessages((prev) => GiftedChat.append(prev, messages));
  await test(messages[0].text);
}, []);

const onLongPress = (context, message) => {
  setMessages((prev) =>
    prev.map((msg) =>
      msg._id === message._id ? { ...msg, isStarred: !msg.isStarred } : msg
    )
  );
};

const renderSend = (props) => (
  <View style={{ flexDirection: "row", alignItems: "center", padding: 14 }}>
    <Send {...props} containerStyle={styles.sendButton}>
      <Ionicons name="paper-plane" size={20} color="white" />
    </Send>
  </View>
);

const renderBubble = (props) => (
  <Bubble
    {...props}
    wrapperStyle={{
      left: { backgroundColor: Colors.card },
      right: { backgroundColor: Colors.primary },
    }}
    renderTime={() => (
      <View style={styles.timeContainer}>
        <Text style={styles.timeText}>
          {new Date(props.currentMessage.createdAt).toLocaleTimeString([], {
            hour: "2-digit",
            minute: "2-digit",
          })}
        </Text>
        {props.currentMessage.isStarred && (
          <Ionicons name="star" size={15} color="#FFD700" />
        )}
      </View>
    )}
  />
);

return (
  <SafeAreaView
    style={{
      flex: 1,
      backgroundColor: "white",
      paddingBottom: insets.bottom,
    }}
  >
    <GiftedChat
      messages={messages}
      onSend={onSend}
      user={{ _id: 1 }}
      isTyping={isTyping}
      renderBubble={renderBubble}
      renderSend={renderSend}
      onLongPress={onLongPress}
      text={text}
      onInputTextChanged={setText}
      maxComposerHeight={100}
      textInputProps={styles.inputMsg}
    />
  </SafeAreaView>
  );
};

const styles = {
  timeContainer: { flexDirection: "row", alignItems: "center" },
  timeText: { fontSize: 12, color: "#666", marginRight: 5 },
  sendButton: {
    backgroundColor: Colors.primary,
    padding: 10,
    borderRadius: 10,
    justifyContent: "center",
    alignItems: "center",
  },
  inputMsg: {
    backgroundColor: Colors.card,
    borderWidth: 1,
    borderRadius: 10,
    borderColor: "#666",
    paddingHorizontal: 10,
    fontSize: 16,
    marginVertical: 4,
    paddingTop: 8,
  },
};

 export default ChatScreen; `

Additional Information

  • Nodejs version: v20.12.1
  • React version: 18.2.0
  • React Native version: 0.74.5
  • react-native-gifted-chat version: 2.6.4
  • Platform(s) (iOS, Android, or both?): Android
  • TypeScript version: 5.3.3
@DavidDolyak
Copy link

Any updates on this? Same issue here!

@DavidDolyak
Copy link

Instead of passing onSend function to the chat I am passing it directly to the InputToolbar component. This resolved my issue. I hope it helps!

@m-eraf
Copy link

m-eraf commented Nov 2, 2024

same issue anyone know the solution?

@habasefa
Copy link

same issue here. any update

@altunf
Copy link
Author

altunf commented Nov 22, 2024

I’ve resolved the issue. Below are the updated versions and a brief explanation of the changes made.

Updated Versions

Expo: ^52.0.7
React Native: 0.76.2
React: ^18.3.1

Changes

Message ID: Replaced Date.now() with Crypto.randomUUID().
onSend Function: Updated to onSend={(messages) => onSend(messages)}.

Updated ChatScreen Component

import React, { useState, useCallback, useEffect } from "react";
import { View, Text } from "react-native";
import {
  GiftedChat,
  Send,
  InputToolbar,
  Bubble,
} from "react-native-gifted-chat";
import { Ionicons } from "@expo/vector-icons";
import ChatbotAvatar from "../../../assets/images/logo.png";
import UserAvatar from "../../../assets/avatars/2.png";
import { useAuthContext } from "@/context/AuthProvider";
import { postChatText } from "../../../services/psychology";
import { useGlobalContext } from "../../../context/GlobalProvider";
import * as Crypto from "expo-crypto";
import { Colors } from "../../../constants/Colors";
import { Texts } from "../../../constants/Texts";

const ChatScreen = () => {
  const { authState } = useAuthContext();
  const { chatModelId } = useGlobalContext();
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    setMessages([
      {
        _id: 1,
        text: `Hello ${authState.username}!`,
        createdAt: new Date(),
        user: {
          _id: 2,
          name: "Chatbot",
          avatar: ChatbotAvatar,
        },
      },
    ]);
  }, []);

  const onSend = useCallback(
    async (messages = []) => {
      setMessages((previousMessages) =>
        GiftedChat.append(previousMessages, messages)
      );

      const userMessage = messages[0].text;

      try {
        const response = await postChatText({
          userId: authState.userId,
          text: userMessage,
          modelId: chatModelId,
          token: authState.token,
        });

        const botMessage = {
          _id: Crypto.randomUUID(),
          text: response?.data?.text,
          createdAt: new Date(),
          user: {
            _id: 2,
            name: "Chatbot",
            avatar: ChatbotAvatar,
          },
        };

        setMessages((previousMessages) =>
          GiftedChat.append(previousMessages, [botMessage])
        );
      } catch (error) {
        console.error("Error fetching the API:", error);
      }
    },
    [authState.userId, authState.token, chatModelId]
  );

  const renderSend = (props) => (
    <Send {...props}>
      <View style={styles.sendIconContainer}>
        <Ionicons name="send" style={styles.sendIcon} size={25} color="black" />
      </View>
    </Send>
  );

  const scrollToBottomComponent = () => (
    <Ionicons name="arrow-down-circle" size={28} color="black" />
  );

  const renderBubble = (props) => (
    <Bubble
      {...props}
      textStyle={{
        left: { color: "black", fontFamily: Texts.caption.md.fontFamily },
        right: { color: "white", fontFamily: Texts.caption.md.fontFamily },
      }}
      wrapperStyle={{
        left: { backgroundColor: Colors.highlight.xs, padding: 5 },
        right: { backgroundColor: Colors.highlight.lg, padding: 5 },
      }}
    />
  );

  return (
    <View style={styles.container}>
      <GiftedChat
        isTyping={false}
        renderSend={renderSend}
        scrollToBottom
        scrollToBottomComponent={scrollToBottomComponent}
        renderInputToolbar={(props) => (
          <InputToolbar {...props} containerStyle={styles.inputToolbar} />
        )}
        placeholder="Ask something to chatbot ..."
        messages={messages}
        onSend={(messages) => onSend(messages)}
        user={{
          _id: authState.userId,
          name: authState.username,
          avatar: UserAvatar,
        }}
        renderChatFooter={() => (
          <Text style={styles.chatFooter}>footer msg</Text>
        )}
        renderBubble={renderBubble}
      />
    </View>
  );
};

const styles = {
  container: {
    flex: 1,
    backgroundColor: "white",
  },
  sendIconContainer: {
    flexDirection: "row",
  },
  sendIcon: {
    marginBottom: 10,
    marginRight: 10,
    color: Colors.highlight.xl,
  },
  inputToolbar: {
    borderRadius: 20,
    backgroundColor: Colors.highlight.xs,
    marginHorizontal: 10,
    marginTop: 5,
    borderTopWidth: 0,
    marginBottom: 10,
  },
  chatFooter: {
    color: "gray",
    margin: "auto",
    ...Texts.action.md,
    marginBottom: 10,
    textAlign: "center",
  },
};

export default ChatScreen;

eas.json Configuration

{
  "cli": {
    "version": ">= 12.5.4",
    "appVersionSource": "remote"
  },
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "preview": {
      "distribution": "internal",
      "android": { "buildType": "apk" }
    },
    "production": {
      "autoIncrement": true
    }
  },
  "submit": {
    "production": {}
  }
}

EAS Build Command

eas build --profile preview --platform android

@ashikhp
Copy link

ashikhp commented Nov 23, 2024

Issue is with the onSend props of react-native-gifetd-chat

Updated versions

Expo: ^52.0.7
React Native: 0.76.2
React: ^18.3.1
react-native-gifted-chat: ^2.6.4

Updated code


import React, { useState } from "react";
import { View, StyleSheet, TextInput, TouchableOpacity, Text } from "react-native";
import { GiftedChat } from "react-native-gifted-chat";

const ChatScreen = () => {
  const [messages, setMessages] = useState([]);
  const [text, setText] = useState("");

  const onSend = (newMessages = []) => {
    setMessages((prevMessages) => GiftedChat.append(prevMessages, newMessages));
    setText(""); // Clear the input field after sending
  };

  const renderInputToolbar = () => (
    <View style={styles.customToolbar}>
      <TextInput
        style={styles.input}
        value={text}
        onChangeText={(value) => setText(value)}
        placeholder="Type a message..."
        placeholderTextColor={"#c1c1c1"}
      />
      <TouchableOpacity
        style={styles.sendButton}
        onPress={() => {
          if (text.trim()) {
            onSend([
              {
                _id: Math.random().toString(), // Unique ID for the message
                text,
                createdAt: new Date(),
                user: { _id: 1, name: "User" },
              },
            ]);
          }
        }}
      >
        <Text style={styles.sendText}>Send</Text>
      </TouchableOpacity>
    </View>
  );

  return (
    <View style={styles.container}>
      <GiftedChat
        messages={messages}
        user={{
          _id: 1,
          name: "User",
        }}
        renderInputToolbar={renderInputToolbar} // Use the custom toolbar
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
  },
  customToolbar: {
    flexDirection: "row",
    alignItems: "center",
    padding: 10,
    borderTopWidth: 1,
    borderTopColor: "#ccc",
    backgroundColor: "#f9f9f9",
  },
  input: {
    flex: 1,
    padding: 10,
    borderRadius: 20,
    borderWidth: 1,
    borderColor: "#ccc",
    backgroundColor: "#fff",
    marginRight: 10,
  },
  sendButton: {
    backgroundColor: "#007bff",
    paddingHorizontal: 15,
    paddingVertical: 10,
    borderRadius: 20,
  },
  sendText: {
    color: "#fff",
    fontWeight: "bold",
  },
});

export default ChatScreen;

@aaronleo28
Copy link

The issue is with the message id generator function. You can override this using the messageIdGenerator prop

if you want to generate a uuid you can use either of these libs expo-crypto or react-native-uuid

import uuid from 'react-native-uuid';

<GiftedChat
    ...
    messageIdGenerator={() => uuid.v4() as string}
/>

@jlparnisari
Copy link

So what is the gifted chat solution?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants