-
Notifications
You must be signed in to change notification settings - Fork 354
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]);