Skip to content

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

@sudorishabh

Description

@sudorishabh

Description:

Some of the core components — EmbeddedChat, ChatBody, and ChatInput — were subscribing to RCInstance.auth.onAuthChange() inside useEffect hooks, but they didn’t include a cleanup function to unsubscribe when the component unmounted.

Because of this, two main problems were happening:

  1. Memory leaks (duplicate listeners): Every time these components re-rendered or mounted again — which happens often in environments like Storybook or when switching channels — a new listener was added to the shared authListeners array. The old listeners were never removed, so they kept running in the background as “ghost” listeners, slowly consuming memory and processing power.

  2. Race conditions (state updates after unmount): The onAuthChange logic in RocketChatAuth.ts runs asynchronously. If a component unmounted while the authentication status was still being fetched, the callback could still fire for that component even though it was already gone. This could lead to React warnings about updating state on an unmounted component and might also cause inconsistent app behavior.

This is a preventative fix that ensures the application remains performant and stable as it grows, preventing memory bloat and redundant logic execution during long-running sessions.

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]);

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions