RocketChat / RocketChat/EmbeddedChat
Fix: Memory leaks and race conditions in auth event listeners across React components
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 165
- Forks
- 381
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 1
Description
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:
-
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.
-
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]);
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Locate the EmbeddedChat, ChatBody, and ChatInput components and read RocketChatAuth.ts to trace the auth listener lifecycle. Check how each component subscribes and tears down its listeners, then verify that unmounting prevents further callbacks and duplicate listeners. Run the relevant existing component tests if available.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, react
- Domain
- authentication, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100