1. 启动性能优化
1. 代码层面的优化
1.1 延迟加载 (Code Splitting)
- 不要在
App.tsx
就加载所有模块。 - 对一些"次要页面"、"功能模块"使用 动态 import。
tsx
// App.tsx
import { Suspense, lazy } from 'react';
const Settings = lazy(() => import('./screens/Settings'));
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen
name="Settings"
component={() => (
<Suspense fallback={<Loading />}>
<Settings />
</Suspense>
)}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
✅ 避免在冷启动时加载大量无关模块。
1.2 按需注册 Native 模块
React Native 默认会在启动时加载所有 Native 模块。
在 Android/iOS 原生侧,可以按需初始化模块,避免阻塞启动。
Android 示例(懒加载模块)
java
@Override
public List<ReactPackage> createViewManagers(ReactApplicationContext reactContext) {
List<ViewManager> managers = new ArrayList<>();
if (FeatureFlags.isChatEnabled()) {
managers.add(new ChatViewManager());
}
return managers;
}
✅ 避免加载用不到的 Native 组件。
1.3 避免大 JSON / 大数据在启动时加载
如果你在启动时就解析大 JSON,会导致 JS Thread 卡顿。
👉 建议在 Splash 页面延迟加载,或者在 Native 层预处理。
tsx
// ❌ 不推荐:App 启动立即解析大数据
const data = require('./large-data.json');
// ✅ 推荐:按需加载
useEffect(() => {
import('./large-data.json').then(module => {
setData(module.default);
});
}, []);
2. 打包与构建优化
2.1 启用 Hermes 引擎
Hermes 提升启动性能最明显。
- Android:
android/app/build.gradle
gradle
project.ext.react = [
enableHermes: true
]
- iOS: Podfile
ruby
use_react_native!(
:hermes_enabled => true
)
2.2 拆分 Bundle
在 metro.config.js
里使用 splitBundle
或第三方方案拆分基础包 + 业务包,减少主包体积。
js
// metro.config.js
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true, // ✅ 推荐:加快启动
},
}),
},
};
✅ inlineRequires: true
可以延迟加载模块,提升冷启动速度。
2.3 Android 多架构分包
在 app/build.gradle
配置:
gradle
splits {
abi {
enable true
reset()
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
universalApk false
}
}
✅ 减少 APK 体积,降低下载/安装耗时。
3. 原生侧优化
3.1 Android:延迟初始化 SoLoader
java
@Override
public void onCreate() {
super.onCreate();
// ❌ 默认:阻塞启动
// SoLoader.init(this, false);
// ✅ 推荐:延迟初始化,等用户点击 RN 页面时再初始化
new Handler().post(() -> SoLoader.init(this, false));
}
3.2 iOS:减少主线程阻塞
在 AppDelegate.mm
中,避免在 application:didFinishLaunchingWithOptions
里做过多初始化,把非关键逻辑移到异步队列。
objc
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ✅ 关键逻辑保留
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
// ✅ 非关键逻辑延迟执行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self initializeAnalytics];
[self preloadData];
});
return YES;
}
4. 用户感知优化
4.1 Splash Screen + 占位页
使用 react-native-bootsplash
,避免用户在白屏时感知卡顿。
js
import RNBootSplash from "react-native-bootsplash";
useEffect(() => {
async function init() {
await loadResources();
RNBootSplash.hide({ fade: true });
}
init();
}, []);
4.2 预加载关键数据
在 Native 层预加载关键数据(比如用户 token、配置),在 RN 初始化时直接注入,避免 RN 再次异步请求。
java
// Android Example
@Override
protected String getJSMainModuleName() {
JSONObject preloadData = new JSONObject();
preloadData.put("token", SharedPref.getToken());
return "index";
}
2. 渲染性能优化
1. 避免不必要的重渲染
使用 React.memo
tsx
// 子组件:只在 props 改变时更新
const Item = React.memo(({ title }: { title: string }) => {
console.log('Render Item:', title);
return <Text>{title}</Text>;
});
// 父组件
export default function List({ data }: { data: string[] }) {
return data.map((title, i) => <Item key={i} title={title} />);
}
✅ 优势:当父组件更新时,如果 title
没有变化,Item
不会重新渲染。
2. 缓存函数与计算结果
使用 useCallback
缓存函数
tsx
function UserList({ users }: { users: string[] }) {
const [selected, setSelected] = useState<string | null>(null);
// ❌ 每次渲染都会创建新函数,导致子组件重渲染
// const handlePress = (user: string) => setSelected(user);
// ✅ useCallback 缓存函数
const handlePress = useCallback((user: string) => {
setSelected(user);
}, []);
return (
<FlatList
data={users}
renderItem={({ item }) => (
<UserItem user={item} onPress={handlePress} />
)}
keyExtractor={item => item}
/>
);
}
const UserItem = React.memo(({ user, onPress }: { user: string; onPress: (u: string) => void }) => {
console.log('Render User:', user);
return (
<Pressable onPress={() => onPress(user)}>
<Text>{user}</Text>
</Pressable>
);
});
✅ 优势:onPress
引用不会改变,UserItem
不会重复渲染。
使用 useMemo
缓存计算结果
tsx
function ExpensiveList({ data }: { data: number[] }) {
// ❌ 每次渲染都要执行复杂计算
// const sorted = data.sort((a, b) => a - b);
// ✅ useMemo 缓存结果
const sorted = useMemo(() => {
console.log('Sorting...');
return [...data].sort((a, b) => a - b);
}, [data]);
return (
<View>
{sorted.map(n => (
<Text key={n}>{n}</Text>
))}
</View>
);
}
✅ 优势:只有 data
变化时才重新计算排序。
3. FlatList 优化
正确设置 keyExtractor
tsx
<FlatList
data={messages}
renderItem={({ item }) => <MessageItem message={item} />}
keyExtractor={item => item.id.toString()} // ✅ 使用稳定的 key
/>
✅ 避免因为 key
不稳定而导致的整列表重渲染。
使用 getItemLayout
提升滚动性能
如果列表项固定高度,可以提供布局信息,避免运行时测量。
tsx
<FlatList
data={users}
renderItem={renderItem}
keyExtractor={item => item.id}
getItemLayout={(data, index) => ({
length: 60, // 每项高度
offset: 60 * index, // 偏移量
index,
})}
/>
✅ 优势:提升长列表滚动性能,支持快速跳转定位。
4. 避免嵌套过深 & inline 样式
❌ 不推荐:每次渲染都新建对象
tsx
<View style={{ padding: 10, backgroundColor: 'red' }} />
✅ 推荐:StyleSheet.create
tsx
const styles = StyleSheet.create({
box: {
padding: 10,
backgroundColor: 'red',
},
});
<View style={styles.box} />
✅ 优势:避免每次渲染都创建新对象,提升 diff 效率。
5. 使用 Placeholder / Skeleton UI
避免加载时白屏卡顿。
tsx
function SkeletonItem() {
return (
<View style={{ flexDirection: 'row', marginBottom: 10 }}>
<View style={{ width: 50, height: 50, backgroundColor: '#ccc', borderRadius: 25 }} />
<View style={{ flex: 1, marginLeft: 10 }}>
<View style={{ width: '80%', height: 20, backgroundColor: '#ccc', marginBottom: 6 }} />
<View style={{ width: '60%', height: 20, backgroundColor: '#ccc' }} />
</View>
</View>
);
}
export default function UserList({ loading, data }: { loading: boolean; data: string[] }) {
if (loading) {
return (
<View>
{Array.from({ length: 5 }).map((_, i) => (
<SkeletonItem key={i} />
))}
</View>
);
}
return data.map((name, i) => <Text key={i}>{name}</Text>);
}
✅ 优势:让用户在加载时看到平滑过渡,减少卡顿感知。
3. 动画优化
3.1 使用 react-native-reanimated 替代 JS 驱动动画
避免 JS Thread 卡顿导致掉帧。
tsx
import Animated, { useSharedValue, withSpring, useAnimatedStyle } from 'react-native-reanimated';
export default function Box() {
const offset = useSharedValue(0);
const style = useAnimatedStyle(() => ({
transform: [{ translateX: offset.value * 100 }],
}));
return (
<Animated.View
style={[{ width: 100, height: 100, backgroundColor: 'blue' }, style]}
onTouchStart={() => {
offset.value = withSpring(Math.random());
}}
/>
);
}
4. 内存与资源优化
1. 避免内存泄漏
1.1 清理定时器 / 订阅 / 动画
tsx
// ❌ 不推荐:组件卸载后,定时器还在跑
useEffect(() => {
const id = setInterval(fetchData, 1000);
}, []);
// ✅ 推荐:卸载时清理
useEffect(() => {
const id = setInterval(fetchData, 1000);
return () => clearInterval(id);
}, []);
同样的原则适用于 事件订阅 、动画 、WebSocket。
1.2 使用 AbortController 取消未完成的请求
避免组件卸载后还在处理网络请求。
tsx
useEffect(() => {
const controller = new AbortController();
fetch('https://api.example.com/data', { signal: controller.signal })
.then(res => res.json())
.then(setData)
.catch(err => {
if (err.name !== 'AbortError') console.error(err);
});
return () => controller.abort(); // ✅ 组件卸载时取消请求
}, []);
2. 图片与资源优化
2.1 使用缓存库(FastImage)
tsx
import FastImage from 'react-native-fast-image';
<FastImage
style={{ width: 200, height: 200 }}
source={{
uri: 'https://example.com/img.jpg',
priority: FastImage.priority.high,
cache: FastImage.cacheControl.immutable,
}}
resizeMode={FastImage.resizeMode.cover}
/>
✅ 支持磁盘缓存 / 内存缓存,避免重复下载。
2.2 避免加载超大图
- 服务器端提供多分辨率(xxhdpi, xxxhdpi)资源。
- 前端按需选择:
tsx
<Image
source={{ uri: isHighRes ? bigUrl : smallUrl }}
style={{ width: 100, height: 100 }}
/>
2.3 本地资源压缩与合理格式
- WebP/AVIF 替代 PNG/JPEG → 体积减小 30%~70%。
- 使用
Image.getSize()
预先获取尺寸,避免 OOM。
tsx
Image.getSize(url, (width, height) => {
console.log(`image size: ${width}x${height}`);
});
3. 列表资源优化
3.1 卸载屏幕外组件
FlatList
配合 removeClippedSubviews
:
tsx
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
removeClippedSubviews={true} // ✅ 移除屏幕外组件
/>
✅ 节省内存占用,避免同时保留大量元素。
3.2 复用列表 Cell(RecyclerListView)
对于超长列表,可以用 RecyclerListView 替代 FlatList,提高内存利用率。
tsx
import { RecyclerListView, DataProvider, LayoutProvider } from 'recyclerlistview';
4. 文件与缓存管理
4.1 定期清理缓存
可用 react-native-fs
定期清理不再需要的文件。
tsx
import RNFS from 'react-native-fs';
async function clearCache() {
const cacheDir = RNFS.CachesDirectoryPath;
const files = await RNFS.readDir(cacheDir);
for (const file of files) {
await RNFS.unlink(file.path);
}
}
4.2 Android 大文件优化
- 使用
content://
URI + 流式读取,避免一次性加载到内存。 - 使用
BitmapFactory.Options.inSampleSize
缩小大图。
java
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4; // 降低分辨率
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
4.3 iOS 图片内存优化
- 使用
UIImage imageWithContentsOfFile
代替imageNamed
,避免缓存过多图片到内存。 - 在
RCTImageLoader
层设置maxMemoryCacheSize
限制。
5. 调试与监控
5.1 开发调试
- Flipper Memory 插件:监控 JS/Native 内存使用情况。
- Xcode Instruments:分析 iOS 内存泄漏。
- Android Profiler:查看对象分配 & 内存占用。
5.2 线上监控
- 接入 Sentry/Datadog/Bugly → 收集内存崩溃/OOM。
5. 跨端通信优化
5.1 减少 Bridge 次数
合并多次调用为一次调用,特别是高频场景。
tsx
// ❌ 不推荐 - 每次 setState 都会触发 Bridge
for (const item of list) {
NativeModules.MyModule.save(item);
}
// ✅ 推荐 - 一次性传递
NativeModules.MyModule.saveAll(list);
6. 生产构建优化
6.1 Hermes 引擎
RN 0.64+ 默认支持 Hermes,启用后 JS 执行更快,内存占用更小。
在 android/app/build.gradle
:
gradle
project.ext.react = [
enableHermes: true // 打开 Hermes
]
iOS 也可以在 Podfile 里启用 Hermes。
✅ 总结(落地方案)
- 启动优化:延迟加载模块,SoLoader 延迟初始化。
- 渲染优化 :
memo
、useCallback
,FlatList 参数调优。 - 动画优化:使用 Reanimated,避免 JS Thread 驱动动画。
- 资源优化:FastImage 缓存、清理定时器避免泄漏。
- 通信优化:减少 RN ↔ Native Bridge 次数。
- 构建优化:启用 Hermes,减小包体积 & 提升执行效率。