React Native 性能:我首先测量和修复的内容
Source: Dev.to

我测量的内容
-
启动时间 – 从点击到首次有意义的渲染(例如,首页可见)的时间。
工具: Flipper、React Native 内置的性能工具,或在原生代码中加入简单的时间戳。对比更改前后的数据(新库、更多初始数据),以避免回退。 -
帧率(FPS) – 尤其是在滚动和动画时。
工具: React Native 的 “Show Perf Monitor” 或 Flipper(显示 JS 线程和 UI 线程的 FPS)。FPS 低于 60(在支持的设备上低于 120)表明卡顿。记录是哪一个页面或列表导致的。 -
列表滚动 – 长列表是常见瓶颈。
检查:- 是否在使用
FlatList(或类似组件)? - 是否渲染了过多的项或每行的组件过于沉重?
- 滚动时是否在 JS 线程上做了大量工作?
- 是否在使用
-
内存 – 关注泄漏(内存随时间增长)和大块分配。
工具: Flipper 或 Xcode/Android Studio 性能分析器。泄漏常来源于图片、缓存或未清理的监听器。 -
包体大小 – 大的 JS 包会拖慢启动。
运行npx react-native bundle --dev false并检查输出大小。寻找可以懒加载或替换的重量级依赖。
每个版本的基线
在每个版本记录一小组关键指标(例如,启动时间、主 feed 列表的 FPS、5 分钟后的内存)。将它们存放在文档或 CI 流水线中。当新功能上线时,与基线对比,回退会变得一目了然,而不是“感觉更慢”。
我首先尝试的修复
列表
// Example: enabling getItemLayout for fixed‑height items
const getItemLayout = (data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
});
- 使用
FlatList(或FlashList以获得更高吞吐量)。 - 当项高度固定时实现
getItemLayout。 - 调整
windowSize和maxToRenderPerBatch,限制树中项的数量。 - 对列表项组件进行 memo,避免在每次滚动时重新渲染。
- 避免在
renderItem中使用内联函数和对象字面量;传递稳定的 props。
图片
- 合理使用
resizeMode。 - 从后端或能够自动裁剪的 CDN 提供合适尺寸的图片。
- 考虑使用
react-native-fast-image以获得更好的缓存。 - 在列表中对屏幕外的图片进行懒加载。
重新渲染
const MemoizedComponent = React.memo(MyComponent);
const stableCallback = useCallback(() => { /* … */ }, []);
const stableValue = useMemo(() => computeExpensiveValue(), []);
- 使用 React DevTools Profiler 或 “Highlight updates” 检测不必要的重新渲染。
- 提升状态,使只有需要的部分重新渲染。
- 避免在 render 中或频繁运行的 effect 中设置状态。
JS 线程
- 将重工作业移出 JS 线程:使用原生模块进行密集计算,或使用
InteractionManager.runAfterInteractions批处理工作。 - 避免在启动或滚动期间在主 JS 线程上执行大型同步操作。
启动
- 减少初始 JS 包体大小:懒加载页面(
React.lazy+ 代码拆分,在支持的情况下),推迟非关键导入,精简依赖。 - 如未开启 Hermes,请启用;它通常能提升启动时间和内存使用。
清理
- 在
useEffect的清理函数中取消订阅、清除定时器、取消请求。 - 移除事件监听器并关闭连接,以防止内存泄漏或不必要的后台工作。
我一次只处理一个领域,重新测量,再重复。小而可验证的改进会累计;没有测量的随意“优化”往往不起作用。
Saad Mehmood — Portfolio