React Native · Mobile UI at native speed
How do you find and fix memory leaks?
Short answer
Look for listeners, timers, subscriptions and async callbacks that outlive a screen, clean them up in effects, and confirm with native memory tools rather than guessing from a rising graph.
A React Native leak is usually a retained reference: a global event subscription that still points at a component, a timer that never clears, or a promise that resolves after unmount and calls setState. The JS heap grows, or native views stay alive after navigation.
import { useEffect, useState } from "react";
import { Keyboard } from "react-native";
export function useKeyboardHeight() {
const [height, setHeight] = useState(0);
useEffect(() => {
const show = Keyboard.addListener("keyboardDidShow", (event) => {
setHeight(event.endCoordinates.height);
});
const hide = Keyboard.addListener("keyboardDidHide", () => setHeight(0));
return () => {
show.remove();
hide.remove();
};
}, []);
return height;
}Common leak sources
- AppState, Keyboard, NetInfo and navigation listeners without cleanup
- setInterval or setTimeout that is never cleared
- Async requests that update state after unmount, unless aborted
- Global stores or event emitters retaining screen callbacks
- Large images or base64 strings kept in state or caches
- WebViews and native views that are not torn down properly
AbortController is the clean fix for in-flight requests. Pass its signal to fetch and abort in the effect cleanup. For subscriptions, return the library's remove function rather than a custom flag that only suppresses the warning.
Follow-ups you should expect
Interviewers use these to check whether the first answer was understanding or memorisation.
- 1Why does an uncleared interval leak memory?
- 2How do you cancel a fetch when a screen unmounts?
- 3How do you confirm a leak with a heap snapshot?
- 4Why is a global event emitter a common leak source?
Say it in the interview
I look for references that outlive a screen: listeners, timers, subscriptions and async callbacks. Each effect that subscribes returns a cleanup, and requests get an AbortController so they cannot update state after unmount. To confirm, I take heap snapshots around a repeated navigation flow and compare retained objects rather than trusting a rising memory graph.
Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.
Related questions
Reading is step one
Now say it out loud.
Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live React Native mock interview and get scored feedback on depth, clarity and confidence.