The slow part of an app is rarely where you expect, so measure first, with the tool that fits the question: React 7,897 's <Profiler> or the DevTools Profiler for renders (Components and Profiler), the DevTools Performance panel or a Hermes 11,328 CPU profile for the JavaScript thread (Profiling BookNest), adb shell am start -W for startup, the dev menu's Perf Monitor and dumpsys gfxinfo for dropped frames (Systrace and Android Profiling), and the DevTools Memory panel for growth. React's <Profiler> component reports each commit of the tree inside it, so an app can log its own numbers. The demo wraps two lists of the six books in one each:
const onRender: ProfilerOnRenderCallback = (id, phase, actualMs) => {
console.log(`${id} ${phase}: ${renders[id]} rows rendered in ${actualMs.toFixed(1)} ms`);
renders[id] = 0;
};
// ...
<Profiler id="plain" onRender={onRender}><PlainList letter={letter} /></Profiler>
<Profiler id="memo" onRender={onRender}><MemoList /></Profiler>actualMs is the time React spent rendering the subtree in that commit. Measure release builds where it matters: a debug build runs extra checks and loads unoptimized JavaScript from Metro. Compare numbers only within one build and one device, and repeat each measurement, because single runs on this shared emulator varied by a factor of two.