Skip to content

Fix/auth listener leaks#1197

Draft
sudorishabh wants to merge 4 commits intoRocketChat:developfrom
sudorishabh:fix/auth-listener-leaks
Draft

Fix/auth listener leaks#1197
sudorishabh wants to merge 4 commits intoRocketChat:developfrom
sudorishabh:fix/auth-listener-leaks

Conversation

@sudorishabh
Copy link

Fix: Cleanup auth listeners on component unmount to prevent memory leaks

fix: #1196

What does this PR do?

While reviewing the auth event listeners in our core React components, I noticed a potential silent memory leak and race condition.

In EmbeddedChat, ChatBody, and ChatInput, we were subscribing to RCInstance.auth.onAuthChange() inside useEffect, but we weren’t cleaning up those subscriptions when the components unmounted or re-rendered. This means that on every re-render, a new callback would get added to the authListeners array and stay there indefinitely.

In this PR I:

Refactored the anonymous inline callbacks into named functions.

Added proper cleanup in the useEffect hooks using return () => RCInstance.auth.removeAuthListener(handleAuthChange);

Before

useEffect(() => {
  RCInstance.auth.onAuthChange((user) => {
    if (user) {
      RCInstance.addMessageListener(addMessage);
      RCInstance.addMessageDeleteListener(removeMessage);
      RCInstance.addActionTriggeredListener(onActionTriggerResponse);
      RCInstance.addUiInteractionListener(onActionTriggerResponse);
    }
  });

  return () => {
    RCInstance.removeMessageListener(addMessage);
    RCInstance.removeMessageDeleteListener(removeMessage);
    RCInstance.removeActionTriggeredListener(onActionTriggerResponse);
    RCInstance.removeUiInteractionListener(onActionTriggerResponse);
  };
}, [RCInstance, addMessage, removeMessage, onActionTriggerResponse]);

After

  useEffect(() => {
    const handleAuthChange = (user) => {
      if (user) {
        RCInstance.addMessageListener(addMessage);
        RCInstance.addMessageDeleteListener(removeMessage);
        RCInstance.addActionTriggeredListener(onActionTriggerResponse);
        RCInstance.addUiInteractionListener(onActionTriggerResponse);
      }
    };

    RCInstance.auth.onAuthChange(handleAuthChange);

    return () => {
      RCInstance.auth.removeAuthListener(handleAuthChange);
      RCInstance.removeMessageListener(addMessage);
      RCInstance.removeMessageDeleteListener(removeMessage);
      RCInstance.removeActionTriggeredListener(onActionTriggerResponse);
      RCInstance.removeUiInteractionListener(onActionTriggerResponse);
    };
  }, [RCInstance, addMessage, removeMessage, onActionTriggerResponse]);

Files with the issue - EmbeddedChat.js, ChatInput.js, ChatBody.js

Note: The PR will be ready for live testing at https://rocketchat.github.io/EmbeddedChat/pulls/pr-1196 after approval.

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

Successfully merging this pull request may close these issues.

Fix: Memory leaks and race conditions in auth event listeners across React components

1 participant