目录
1. 渲染性能优化
2. 列表性能优化
3. 图片优化
4. 内存优化
5. 启动优化
6. 网络优化
7. 调试工具
8. 原生模块优化
9. 性能检查清单
10. 实战案例
React.memo避免不必要的重渲染1.2 使用// ❌ 低效:父组件更新时子组件总是重渲染
const UserProfile = ({ user, onEdit }) => {
return (
{user.name} Text>
View>
);
};
// ✅ 优化:使用 React.memo 缓存组件
const UserProfile = React.memo(({ user, onEdit }) => {
return (
{user.name} Text>
View>
);
});
// 配合 useMemo 缓存回调函数
const handleEdit = useCallback(() => {
// 处理逻辑
}, []);
useMemouseCallback1.3 避免内联样式和对象// ❌ 低效:每次渲染都创建新对象和函数
const TodoList = ({ todos }) => {
const filteredTodos = todos.filter(t => t.completed);
const handlePress = () => console.log('pressed');
return filteredTodos.map(todo => (
));
};// ✅ 优化:缓存计算结果和回调
const TodoList = React.memo(({ todos }) => {
const filteredTodos = useMemo(
() => todos.filter(t => t.completed),
[todos]
);
const handlePress = useCallback(() => {
console.log('pressed');
}, []);
return filteredTodos.map(todo => (
));
});
1.4 使用// ❌ 低效:每次渲染创建新对象
const Text = () => ;// ✅ 优化:使用 StyleSheet
const styles = StyleSheet.create({
container: { padding: 10, margin: 5 }
});
const Text = () => ;
key优化列表渲染二、列表性能优化 2.1 使用// ❌ 低效:使用 index 作为 key
{items.map((item, index) => (
))}// ✅ 优化:使用唯一 ID 作为 key
{items.map(item => (
))}
FlatList替代ScrollView2.2 实现// ❌ 低效:渲染所有项目
{items.map(item => )}
ScrollView>// ✅ 优化:虚拟列表,只渲染可见区域
data={items}
renderItem={({ item }) => }
keyExtractor={item => item.id}
// 关键优化参数
initialNumToRender={10} // 初始渲染数量
maxToRenderPerBatch={10} // 每批渲染数量
windowSize={5} // 渲染窗口大小
removeClippedSubviews={true} // 移除屏幕外子视图
updateCellsBatchingPeriod={100} // 批量更新间隔
/>
getItemLayout跳过测量2.3 使用const ITEM_HEIGHT = 80;data={items}
renderItem={renderItem}
getItemLayout={(data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
/>
React.memo优化列表项const ListItem = React.memo(({ item, onPress }) => {
return (
onPress(item)}>
{item.title}
Text>
TouchableOpacity>
);
}, (prevProps, nextProps) => {
// 自定义比较函数
return prevProps.item.id === nextProps.item.id;
});2.4 使用SectionList优化分组列表 sections={sections}
keyExtractor={item => item.id}
renderItem={({ item }) => }
renderSectionHeader={({ section }) => }
// 优化参数
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews={true}
/>2.5 长列表优化技巧三、图片优化 3.1 使用合适的图片格式和尺寸// 使用 getItemLayout 避免测量
const getItemLayout = (data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
});
// 使用 extraData 避免不必要的重渲染
data={items}
extraData={selectedId}
renderItem={renderItem}
getItemLayout={getItemLayout}
/>// 使用 CellRendererComponent 自定义渲染
data={items}
CellRendererComponent={React.memo(({ children, ...props }) => (
{children} View>
))}
/>
3.2 使用// ✅ 使用 WebP 格式(更小体积)
// ✅ 根据设备像素比加载合适尺寸
const scale = PixelRatio.getPixelSizeForLayoutSize(1);
const uri = `image_${width * scale}x${height * scale}.webp`;// ✅ 使用缓存
source={{ uri }}
cache="immutable" // 或 "web-only", "cache-only"
/>
react-native-fast-imagenpm install react-native-fast-image3.3 图片懒加载import FastImage from 'react-native-fast-image';
source={{
uri: 'https://example.com/image.jpg',
priority: FastImage.priority.normal,
cache: FastImage.cacheControl.immutable,
}}
resizeMode={FastImage.resizeMode.cover}
/>
3.4 图片预加载import FastImage from 'react-native-fast-image';data={images}
renderItem={({ item }) => (
source={{ uri: item.uri }}
// 仅在可见时加载
/>
)}
/>
3.5 图片压缩import FastImage from 'react-native-fast-image';
// 预加载图片
FastImage.preload([
{ uri: 'https://example.com/image1.jpg' },
{ uri: 'https://example.com/image2.jpg' },
]);// 在列表中预加载下一批图片
const loadNextImages = (currentIndex: number) => {
const nextImages = images.slice(currentIndex + 5, currentIndex + 10);
FastImage.preload(nextImages.map(img => ({ uri: img.url })));
};
# 使用 imagemin 压缩图片
npm install -g imagemin-cli
imagemin images/* --out-dir=dist --plugin=webp --quality=80四、内存优化 4.1 避免内存泄漏4.2 使用// ✅ 正确清理订阅和定时器
useEffect(() => {
const timer = setInterval(() => {}, 1000);
const subscription = eventEmitter.addListener('event', handler);
return () => {
clearInterval(timer);
subscription.remove();
};
}, []);// ✅ 清理异步请求
useEffect(() => {
let cancelled = false;
const loadData = async () => {
const result = await fetchData();
if (!cancelled) {
setData(result);
}
};
loadData();
return () => {
cancelled = true;
};
}, []);
InteractionManager延迟执行4.3 避免大对象持有import { InteractionManager } from 'react-native';// 在动画和交互完成后执行
useEffect(() => {
const task = InteractionManager.runAfterInteractions(() => {
// 执行耗时操作
loadLargeData();
});
return () => task.cancel();
}, []);
4.4 使用// ❌ 低效:大对象一直持有
const [data, setData] = useState(largeData);
// ✅ 优化:按需加载,及时清理
const loadData = async () => {
const result = await fetchLargeData();
setData(result);
};const clearData = () => {
setData(null);
// 触发 GC
};
useRef避免不必要的重渲染4.5 清理事件监听器// ❌ 低效:state 变化触发重渲染
const [count, setCount] = useState(0);// ✅ 优化:ref 变化不触发重渲染
const countRef = useRef(0);
countRef.current = count;
useEffect(() => {
const handleOrientationChange = () => {
// 处理方向变化
};
Dimensions.addEventListener('change', handleOrientationChange);
return () => {
Dimensions.removeEventListener('change', handleOrientationChange);
};
}, []);五、启动优化 5.1 减少初始加载内容// ✅ 分屏加载
const App = () => {
const [isReady, setIsReady] = useState(false);
useEffect(() => {
// 先显示启动屏
InteractionManager.runAfterInteractions(() => {
// 后台加载数据
preloadData().then(() => setIsReady(true));
});
}, []);
if (!isReady) return ;
return ;
};5.2 使用 Hermes 引擎5.3 减少包体积// android/app/build.gradle
project.ext.react = [
enableHermes: true // 启用 Hermes
]// iOS/Podfile
hermes_enabled = true
5.4 代码分割# 分析包体积
npx react-native-bundle-visualizer
# 移除未使用的依赖
npx depcheck# 生产环境移除 console
// babel.config.js
plugins: [
process.env.NODE_ENV === 'production' && [
'transform-remove-console',
{ exclude: ['error', 'warn'] }
]
]
5.5 预加载关键资源// 使用动态导入
const HeavyComponent = lazy(() => import('./HeavyComponent'));// 使用时
}>
Suspense>
六、网络优化 6.1 请求缓存// 预加载字体
useFonts({
'Inter-Regular': require('./assets/fonts/Inter-Regular.ttf'),
});// 预加载图片
const images = {
logo: require('./assets/logo.png'),
background: require('./assets/bg.png'),
};
6.2 请求合并与防抖const cache = new Map();const fetchWithCache = async (url, ttl = 5 * 60 * 1000) => {
const cached = cache.get(url);
if (cached && Date.now() - cached.timestamp < ttl) {
return cached.data;
}
const response = await fetch(url);
const data = await response.json();
cache.set(url, { data, timestamp: Date.now() });
return data;
};
6.3 请求节流// 防抖搜索
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
};// 使用
const searchQuery = useDebounce(query, 300);
const useThrottle = (value, interval) => {
const [throttledValue, setThrottledValue] = useState(value);
const lastUpdated = useRef(Date.now());
useEffect(() => {
const now = Date.now();
if (now - lastUpdated.current >= interval) {
setThrottledValue(value);
lastUpdated.current = now;
} else {
const timer = setTimeout(() => {
setThrottledValue(value);
lastUpdated.current = Date.now();
}, interval - (now - lastUpdated.current));
return () => clearTimeout(timer);
}
}, [value, interval]);
return throttledValue;
};6.4 使用react-query管理服务器状态npm install @tanstack/react-query6.5 批量请求import { useQuery, useMutation, QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 分钟
cacheTime: 10 * 60 * 1000, // 10 分钟
retry: 3,
},
},
});
// 使用
const { data, isLoading, error } = useQuery({
queryKey: ['users', userId],
queryFn: () => fetchUser(userId),
});// 预取数据
queryClient.prefetchQuery({
queryKey: ['users', nextUserId],
queryFn: () => fetchUser(nextUserId),
});
七、调试工具 7.1 Flipper 性能监控// 使用 Promise.all 并行请求
const [users, posts, comments] = await Promise.all([
fetchUsers(),
fetchPosts(),
fetchComments(),
]);// 使用 Promise.allSettled 处理部分失败
const results = await Promise.allSettled([
fetchUsers(),
fetchPosts(),
fetchComments(),
]);
7.2 性能监控代码# 安装 Flipper
npm install react-native-flipper# 插件
- React DevTools
- Network Inspector
- Layout Inspector
- Hermes Debugger
- React Native Performance
7.3 FPS 监控import { Performance } from 'react-native';
// 测量渲染时间
const measureRender = (componentName: string) => {
const mark = `__${componentName}_start`;
Performance.mark(mark);
return () => {
Performance.measure(componentName, mark);
Performance.clearMarks(mark);
};
};// 使用
useEffect(() => {
const endMeasure = measureRender('HomeScreen');
return endMeasure;
}, []);
7.4 使用import { requestAnimationFrame } from 'react-native';
let frameCount = 0;
let lastTime = Date.now();const monitorFPS = () => {
frameCount++;
const now = Date.now();
if (now - lastTime >= 1000) {
console.log(`FPS: ${frameCount}`);
frameCount = 0;
lastTime = now;
}
requestAnimationFrame(monitorFPS);
};
why-did-you-render检测不必要的重渲染npm install @welldone-software/why-did-you-render7.5 使用 React DevTools Profiler// index.js
import whyDidYouRender from '@welldone-software/why-did-you-render';
import React from 'react';if (__DEV__) {
whyDidYouRender(React, {
trackAllPureComponents: true,
});
}
八、原生模块优化 8.1 使用 TurboModules 和 Fabricimport { Profiler } from 'react';
const onRenderCallback = (
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime
) => {
console.log(`${id} 渲染耗时: ${actualDuration}ms`);
};
Profiler>
8.2 原生模块异步调用// 新架构启用
// android/gradle.properties
newArchEnabled=true// ios/Podfile
ENV['RCT_NEW_ARCH_ENABLED'] = '1'
// 避免阻塞 JS 线程
NativeModule.heavyTask(params)
.then(result => {
// 处理结果
})
.catch(error => {
// 处理错误
});8.3 使用 JSI 直接调用原生代码8.4 原生动画优化// 通过 JSI 直接调用,避免桥接开销
global.nativeCallSync = (arg) => {
return someNativeFunction(arg);
};// 同步调用,无桥接延迟
const result = global.nativeCallSync(data);
九、性能检查清单// 使用 react-native-reanimated 运行在 UI 线程
import Animated, { useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
const offset = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ translateY: offset.value }],
};
});// 驱动动画
offset.value = withSpring(100);
优化项
检查方法
目标
渲染帧率
Flipper FPS Monitor
≥ 55 FPS
列表滚动
长列表测试
无卡顿
内存使用
Xcode/Android Profiler
无泄漏
启动时间
adb shell am start -W
< 2s
包体积
npx react-native-bundle-visualizer
iOS < 100MB
网络请求
Network Inspector
减少重复请求
图片大小
检查图片资源
WebP + 合适尺寸
JS 包大小
npx react-native-bundle-visualizer
< 5MB
内存泄漏
LeakCanary/Instruments
无泄漏
冷启动时间
Time to Interactive
< 2s
9.1 Android 性能检查
9.2 iOS 性能检查# 检查启动时间
adb shell am start -W com.yourapp/.MainActivity
# 检查内存
adb shell dumpsys meminfo com.yourapp# 检查 GPU 渲染
adb shell dumpsys gfxinfo com.yourapp
9.3 自动化性能测试# 使用 Instruments 检查
open -a Instruments# 检查工具
- Time Profiler
- Allocations
- Leaks
- Energy Log
// 使用 detox 进行性能测试
describe('Performance', () => {
it('should scroll list smoothly', async () => {
await element(by.id('flatList')).swipe('up', 'fast', 0.5);
// 检查 FPS
});
it('should load within 2 seconds', async () => {
const startTime = Date.now();
await waitFor(element(by.id('homeScreen'))).toBeVisible().withTimeout(2000);
const loadTime = Date.now() - startTime;
expect(loadTime).toBeLessThan(2000);
});
});十、实战案例 10.1 优化前 vs 优化后10.2 电商列表页优化// ❌ 优化前:60 FPS → 30 FPS
const Feed = ({ posts }) => {
return (
{posts.map(post => (
key={post.id}
post={post}
onPress={() => navigation.navigate('Detail', { post })}
/>
))}
ScrollView>
);
};
// ✅ 优化后:稳定 60 FPS
const PostCard = React.memo(({ post, onPress }) => {
const handlePress = useCallback(() => onPress(post), [post, onPress]);
return (
{post.title} Text>
TouchableOpacity>
);
});const Feed = ({ posts }) => {
const navigation = useNavigation();
const handleNavigate = useCallback((post) => {
navigation.navigate('Detail', { post });
}, [navigation]);
return (
data={posts}
renderItem={({ item }) => (
)}
keyExtractor={item => item.id}
initialNumToRender={5}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews={true}
getItemLayout={(data, index) => ({
length: 200,
offset: 200 * index,
index,
})}
/>
);
};
10.3 聊天列表优化// 优化要点:
// 1. FlatList 虚拟列表
// 2. React.memo 缓存商品卡片
// 3. FastImage 图片缓存
// 4. getItemLayout 跳过测量
// 5. 下拉刷新 + 上拉加载
const ProductCard = React.memo(({ product, onPress }) => {
const handlePress = useCallback(() => onPress(product), [product, onPress]);
return (
source={{
uri: product.image,
priority: FastImage.priority.normal,
}}
resizeMode={FastImage.resizeMode.cover}
/>
{product.name} Text>
¥{product.price} Text>
TouchableOpacity>
);
});const ProductList = () => {
const [page, setPage] = useState(1);
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(false);
const loadProducts = async (pageNum: number) => {
if (loading) return;
setLoading(true);
try {
const data = await fetchProducts(pageNum);
setProducts(prev => pageNum === 1 ? data : [...prev, ...data]);
} finally {
setLoading(false);
}
};
const handleLoadMore = () => {
if (!loading) {
setPage(prev => prev + 1);
loadProducts(page + 1);
}
};
return (
data={products}
numColumns={2}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => (
product={item}
onPress={product => navigation.navigate('Detail', { product })}
/>
)}
onRefresh={() => {
setPage(1);
loadProducts(1);
}}
refreshing={loading && page === 1}
onEndReached={handleLoadMore}
onEndReachedThreshold={0.3}
initialNumToRender={10}
maxToRenderPerBatch={20}
windowSize={5}
removeClippedSubviews={true}
getItemLayout={(data, index) => ({
length: 280,
offset: 280 * index,
index,
})}
ListFooterComponent={loading ? : null}
/>
);
};
附录:推荐工具和库// 消息列表优化:
// 1. 倒序显示最新消息
// 2. 自动滚动到底部
// 3. 图片消息懒加载
// 4. 消息气泡复用
const MessageItem = React.memo(({ message, onAvatarPress }) => {
const isMe = message.senderId === currentUserId;
return (
{!isMe && (
onAvatarPress(message.sender)}>
source={{ uri: message.senderAvatar }}
/>
TouchableOpacity>
)}
{message.type === 'image' ? (
source={{ uri: message.content }}
resizeMode={FastImage.resizeMode.cover}
/>
) : (
{message.content} Text>
)}
{formatTime(message.createdAt)} Text>
View>
View>
);
});const ChatList = ({ chatId }) => {
const [messages, setMessages] = useState([]);
const flatListRef = useRef(null);
// 订阅新消息
useEffect(() => {
const subscription = messageService.subscribe(chatId, (newMessage) => {
setMessages(prev => [...prev, newMessage]);
// 自动滚动到底部
InteractionManager.runAfterInteractions(() => {
flatListRef.current?.scrollToEnd({ animated: true });
});
});
return () => subscription.remove();
}, [chatId]);
// 加载历史消息
const loadHistory = async () => {
const history = await messageService.getHistory(chatId);
setMessages(history);
};
useEffect(() => {
loadHistory();
}, [chatId]);
return (
ref={flatListRef}
data={messages}
inverted // 倒序显示
keyExtractor={item => item.id}
renderItem={({ item }) => (
message={item}
onAvatarPress={sender => navigation.navigate('Profile', { sender })}
/>
)}
onEndReached={loadMoreHistory}
onEndReachedThreshold={0.5}
initialNumToRender={20}
maxToRenderPerBatch={20}
windowSize={10}
removeClippedSubviews={true}
maintainVisibleContentPosition={{
minIndexForVisible: 0,
}}
/>
);
};
类别
工具/库
用途
图片
react-native-fast-image
高性能图片加载
动画
react-native-reanimated
UI 线程动画
状态管理
@tanstack/react-query
服务器状态管理
调试
react-native-flipper
调试工具平台
性能检测
why-did-you-render
重渲染检测
包分析
react-native-bundle-visualizer
包体积分析
测试
detox
E2E 性能测试
监控
sentry-react-native
错误和性能监控
参考资料
• React Native 官方文档 - 性能
• React Native 性能优化指南
• Hermes 引擎文档
• Flipper 文档
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.