Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React native randomly crashes with error 'Attempted to remove more RCTKeyboardObserver listeners than added'

My react native project on iOS simulator crashes randomly with this error when I open and close the ChatRoom screen, I guess it's a problem with the react native gifted chat library I'm not sure, that's the only external library I use in that screen.

I have tried Keyboard remove listener solution Keyboard.addListener("keyboardWillShow").remove(); from https://github.com/rgommezz/react-native-offline/issues/55 in my App.js file but it don't work.

I have added the code of the screen where this crash randomly occurs. Project versions are "react": "17.0.2", "react-native": "0.66.4", "react-native-gifted-chat": "^0.16.3".

ChatRoom

const ChatRoom = ({ navigation, route }) => {
  React.useLayoutEffect(() => {
    navigation.setOptions({
      title: name,
    });
  }, [navigation, name]);

  React.useEffect(() => {
    mounted.current = true;
    async function fetch() {
      const response = await getUserData(receiverId);
      if (mounted.current) {
        setChatImage(response.userimg);
        setName(response.name);
      }

      const chat = await getChat(user.uid, userid);

      if (chat) {
        const unsubscribe = firestore()
          .collection("Messages")
          .where("chatid", "==", chat)
          .onSnapshot((querySnapshot) => {
            const messages = querySnapshot
              .docChanges()
              .filter(({ type }) => type === "added")
              .map(({ doc }) => {
                const message = doc.data();
                return {
                  ...message,
                  createdAt: message.createdAt.toDate(),
                };
              })
              .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
            appendMessages(messages);
          });

        return () => unsubscribe();
      }
    }
    fetch();
    return () => (mounted.current = false);
  }, []);

  React.useEffect(() => {
    // set message state
    if (receiverId) {
      if (user.uid !== receiverId) {
        async function fetch() {
          const chat = await getChat(user.uid, userid);
          await markMsgStatus(user.uid, chat);
        }
        fetch();
      }
    }
  }, [receiverId]);

  const appendMessages = React.useCallback(
    (messages) => {
      setMessages((previousMessages) =>
        GiftedChat.append(previousMessages, messages)
      );
    },
    [messages]
  );

  const handleSend = async (messages) => {
    // if there are no chats, create one
    const chat = await getChat(user.uid, userid);
    let chatid;
    if (!chat) {
      chatid = await createChat(user.uid, userid);
    }

    // increment the no of messages in the chat by one
    firestore()
      .collection("Chats")
      .doc(chat ? chat : chatid)
      .set(
        {
          noofmsgs: firestore.FieldValue.increment(1),
        },
        { merge: true }
      )
      .then(() => console.log("message count on chat increased by one"))
      .catch((e) => console.log(e));

    // add the messages
    const writes = messages.map((m) =>
      firestore()
        .collection("Messages")
        .add({
          ...m,
          sent: true,
          received: false,
          senderid: user.uid,
          receiverid: userid,
          chatid: chat ? chat : chatid,
        })
    );
    await Promise.all(writes);

    // add the latest msg to chat
    const writetochat = messages.find((m) =>
      firestore()
        .collection("Chats")
        .doc(chat ? chat : chatid)
        .set(
          {
            latestmsg: m,
            latestmsgsender: user.uid,
            latestmsgreceiver: userid,
          },
          { merge: true }
        )
    );
    await Promise.all(writetochat);
  };

  return (
    <View>
      <GiftedChat
        messages={messages}
        user={{
          _id: user.uid,
        }}
        onSend={handleSend}
        showAvatarForEveryMessage={true}
      />
    </View>
  );
};

export default ChatRoom;

like image 435
CleanCodeOnline Avatar asked Dec 06 '25 02:12

CleanCodeOnline


1 Answers

This is the issue of the package itself. Below is how I fixed it.

  1. Install package npm i patch-package
  2. Create a Folder called patches on the root of the directory
  3. Create a new file name patch-rn-gifted-chat within patch folder
  4. add below code to it
diff --git a/node_modules/react-native-gifted-chat/lib/MessageContainer.js b/node_modules/react-native-gifted-chat/lib/MessageContainer.js
index 193772a..4e80378 100644
--- a/node_modules/react-native-gifted-chat/lib/MessageContainer.js
+++ b/node_modules/react-native-gifted-chat/lib/MessageContainer.js
@@ -55,18 +55,18 @@ export default class MessageContainer extends React.PureComponent {
         this.attachKeyboardListeners = () => {
             const { invertibleScrollViewProps: invertibleProps } = this.props;
             if (invertibleProps) {
-                Keyboard.addListener('keyboardWillShow', invertibleProps.onKeyboardWillShow);
-                Keyboard.addListener('keyboardDidShow', invertibleProps.onKeyboardDidShow);
-                Keyboard.addListener('keyboardWillHide', invertibleProps.onKeyboardWillHide);
-                Keyboard.addListener('keyboardDidHide', invertibleProps.onKeyboardDidHide);
+                this.willShowSub = Keyboard.addListener('keyboardWillShow', invertibleProps.onKeyboardWillShow);
+                this.didShowSub = Keyboard.addListener('keyboardDidShow', invertibleProps.onKeyboardDidShow);
+                this.willHideSub = Keyboard.addListener('keyboardWillHide', invertibleProps.onKeyboardWillHide);
+                this.didHideSub = Keyboard.addListener('keyboardDidHide', invertibleProps.onKeyboardDidHide);
             }
         };
         this.detachKeyboardListeners = () => {
             const { invertibleScrollViewProps: invertibleProps } = this.props;
-            Keyboard.removeListener('keyboardWillShow', invertibleProps.onKeyboardWillShow);
-            Keyboard.removeListener('keyboardDidShow', invertibleProps.onKeyboardDidShow);
-            Keyboard.removeListener('keyboardWillHide', invertibleProps.onKeyboardWillHide);
-            Keyboard.removeListener('keyboardDidHide', invertibleProps.onKeyboardDidHide);
+            this.willShowSub?.remove();
+            this.didShowSub?.remove();
+            this.willHideSub?.remove();
+            this.didHideSub?.remove();
         };
         this.renderTypingIndicator = () => {
             if (Platform.OS === 'web') {

Run command yarn or npm i

like image 142
Akshil Shah Avatar answered Dec 07 '25 19:12

Akshil Shah