name: react-native-performance user-invocable: false description: 在优化React Native应用性能时使用。涵盖FlatList优化、记忆化、图像优化、包大小减少和分析技术。 allowed-tools:
- Read
- Write
- Edit
- Bash
- Grep
- Glob
React Native 性能优化
在优化React Native应用以获得更好性能、更快加载时间和更流畅用户体验时使用此技能。
关键概念
列表性能
针对大数据集优化FlatList:
import React, { useCallback } from 'react';
import { FlatList, View, Text, StyleSheet } from 'react-native';
interface Item {
id: string;
title: string;
}
const ItemComponent = React.memo(({ item }: { item: Item }) => (
<View style={styles.item}>
<Text>{item.title}</Text>
</View>
));
function OptimizedList({ data }: { data: Item[] }) {
const renderItem = useCallback(
({ item }: { item: Item }) => <ItemComponent item={item} />,
[]
);
const keyExtractor = useCallback((item: Item) => item.id, []);
const getItemLayout = useCallback(
(data: any, index: number) => ({
length: 80, // 固定项高度
offset: 80 * index,
index,
}),
[]
);
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={keyExtractor}
getItemLayout={getItemLayout}
// 性能优化
removeClippedSubviews={true}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={50}
initialNumToRender={10}
windowSize={5}
/>
);
}
const styles = StyleSheet.create({
item: {
height: 80,
padding: 16,
borderBottomWidth: 1,
borderBottomColor: '#eee',
},
});
组件记忆化
使用React.memo和useMemo:
import React, { useMemo } from 'react';
import { View, Text } from 'react-native';
interface UserCardProps {
user: {
id: string;
name: string;
email: string;
};
onPress: () => void;
}
// 记忆化组件以预防不必要的重新渲染
const UserCard = React.memo(({ user, onPress }: UserCardProps) => {
return (
<View>
<Text>{user.name}</Text>
<Text>{user.email}</Text>
</View>
);
});
// 记忆化昂贵计算
function UserList({ users }: { users: User[] }) {
const sortedUsers = useMemo(() => {
return [...users].sort((a, b) => a.name.localeCompare(b.name));
}, [users]);
return (
<View>
{sortedUsers.map(user => (
<UserCard key={user.id} user={user} onPress={() => {}} />
))}
</View>
);
}
图像优化
优化图像加载和缓存:
import React from 'react';
import { Image, View } from 'react-native';
import FastImage from 'react-native-fast-image';
// 使用FastImage以获得更好性能
function OptimizedImage({ uri }: { uri: string }) {
return (
<FastImage
style={{ width: 200, height: 200 }}
source={{
uri,
priority: FastImage.priority.normal,
cache: FastImage.cacheControl.immutable,
}}
resizeMode={FastImage.resizeMode.cover}
/>
);
}
// 懒加载图像
function LazyImage({ uri }: { uri: string }) {
return (
<Image
source={{ uri }}
style={{ width: 200, height: 200 }}
resizeMode="cover"
loadingIndicatorSource={require('./placeholder.png')}
/>
);
}
最佳实践
为事件处理器使用useCallback
预防不必要的重新渲染:
import React, { useCallback, useState } from 'react';
import { View, Button, Text } from 'react-native';
function Counter() {
const [count, setCount] = useState(0);
// 坏 - 每次渲染都创建新函数
// const increment = () => setCount(count + 1);
// 好 - 记忆化回调
const increment = useCallback(() => {
setCount(c => c + 1);
}, []);
return (
<View>
<Text>{count}</Text>
<Button title="增加" onPress={increment} />
</View>
);
}
仅使用虚拟化列表
对可滚动内容使用FlatList/SectionList:
// 坏 - 带map的ScrollView(渲染所有项)
<ScrollView>
{items.map(item => (
<ItemComponent key={item.id} item={item} />
))}
</ScrollView>
// 好 - FlatList(虚拟化项)
<FlatList
data={items}
keyExtractor={item => item.id}
renderItem={({ item }) => <ItemComponent item={item} />}
/>
避免在渲染中使用匿名函数
// 坏 - 每次渲染都创建新函数
<FlatList
data={items}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => console.log(item.id)}>
<Text>{item.title}</Text>
</TouchableOpacity>
)}
/>
// 好 - 记忆化渲染函数
const renderItem = useCallback(({ item }: { item: Item }) => (
<ItemRow item={item} onPress={handleItemPress} />
), [handleItemPress]);
<FlatList
data={items}
renderItem={renderItem}
/>
优化包大小
减少JavaScript包大小:
# 分析包
npx react-native-bundle-visualizer
# 启用Hermes引擎(用于Expo的app.json)
{
"expo": {
"jsEngine": "hermes"
}
}
# 启用Hermes(用于裸React Native的android/app/build.gradle)
project.ext.react = [
enableHermes: true
]
# 为Android使用ProGuard(android/app/build.gradle)
def enableProguardInReleaseBuilds = true
代码拆分
为更快初始加载拆分代码:
import React, { lazy, Suspense } from 'react';
import { View, ActivityIndicator } from 'react-native';
// 懒加载重型组件
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<ActivityIndicator />}>
<HeavyComponent />
</Suspense>
);
}
常见模式
防抖搜索
import React, { useState, useCallback, useEffect } from 'react';
import { TextInput, FlatList } from 'react-native';
function SearchableList({ data }: { data: Item[] }) {
const [query, setQuery] = useState('');
const [debouncedQuery, setDebouncedQuery] = useState('');
// 防抖搜索
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedQuery(query);
}, 300);
return () => clearTimeout(timer);
}, [query]);
const filteredData = useMemo(() => {
if (!debouncedQuery) return data;
return data.filter(item =>
item.title.toLowerCase().includes(debouncedQuery.toLowerCase())
);
}, [data, debouncedQuery]);
return (
<>
<TextInput
value={query}
onChangeText={setQuery}
placeholder="搜索..."
/>
<FlatList
data={filteredData}
keyExtractor={item => item.id}
renderItem={({ item }) => <ItemComponent item={item} />}
/>
</>
);
}
优化动画
使用react-native-reanimated实现平滑动画:
import React from 'react';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
} from 'react-native-reanimated';
import { Pressable } from 'react-native';
function AnimatedButton() {
const scale = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));
const handlePressIn = () => {
scale.value = withSpring(0.95);
};
const handlePressOut = () => {
scale.value = withSpring(1);
};
return (
<Pressable onPressIn={handlePressIn} onPressOut={handlePressOut}>
<Animated.View style={[styles.button, animatedStyle]}>
<Text>按我</Text>
</Animated.View>
</Pressable>
);
}
分页
实现高效分页:
import React, { useState, useCallback } from 'react';
import { FlatList, ActivityIndicator } from 'react-native';
function PaginatedList() {
const [data, setData] = useState<Item[]>([]);
const [loading, setLoading] = useState(false);
const [page, setPage] = useState(1);
const loadMore = useCallback(async () => {
if (loading) return;
setLoading(true);
const newData = await fetchData(page);
setData(prev => [...prev, ...newData]);
setPage(p => p + 1);
setLoading(false);
}, [loading, page]);
const renderItem = useCallback(
({ item }: { item: Item }) => <ItemComponent item={item} />,
[]
);
const renderFooter = () => {
if (!loading) return null;
return <ActivityIndicator style={{ margin: 16 }} />;
};
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
onEndReached={loadMore}
onEndReachedThreshold={0.5}
ListFooterComponent={renderFooter}
/>
);
}
记忆化选择器
import React, { useMemo } from 'react';
import { View, Text } from 'react-native';
interface User {
id: string;
name: string;
age: number;
active: boolean;
}
function UserStats({ users }: { users: User[] }) {
const stats = useMemo(() => {
return {
total: users.length,
active: users.filter(u => u.active).length,
averageAge: users.reduce((sum, u) => sum + u.age, 0) / users.length,
};
}, [users]);
return (
<View>
<Text>总数: {stats.total}</Text>
<Text>活跃: {stats.active}</Text>
<Text>平均年龄: {stats.averageAge.toFixed(1)}</Text>
</View>
);
}
图像预加载
import { Image } from 'react-native';
async function preloadImages(imageUrls: string[]) {
const promises = imageUrls.map(url =>
Image.prefetch(url)
);
await Promise.all(promises);
}
// 用法
useEffect(() => {
preloadImages([
'https://example.com/image1.jpg',
'https://example.com/image2.jpg',
]);
}, []);
反模式
不要在生产中使用console.log
// 坏 - 日志减慢生产
console.log('用户数据:', user);
// 好 - 删除或使用__DEV__
if (__DEV__) {
console.log('用户数据:', user);
}
不要内联大型对象
// 坏 - 每次渲染都创建新对象
<Component
style={{ width: 100, height: 100, backgroundColor: '#fff' }}
config={{ option1: true, option2: false }}
/>
// 好 - 使用StyleSheet和常量
const styles = StyleSheet.create({
component: { width: 100, height: 100, backgroundColor: '#fff' },
});
const config = { option1: true, option2: false };
<Component style={styles.component} config={config} />
别忘了清理
// 坏 - 内存泄漏
useEffect(() => {
const timer = setInterval(() => {
console.log('滴答');
}, 1000);
}, []);
// 好 - 清理
useEffect(() => {
const timer = setInterval(() => {
console.log('滴答');
}, 1000);
return () => clearInterval(timer);
}, []);
不要在循环中使用setState
// 坏 - 多个重新渲染
items.forEach(item => {
setData(prev => [...prev, item]);
});
// 好 - 单次更新
setData(prev => [...prev, ...items]);
分析工具
React DevTools分析器
import { Profiler } from 'react';
function onRenderCallback(
id: string,
phase: 'mount' | 'update',
actualDuration: number
) {
console.log(`${id} (${phase}) 耗时 ${actualDuration}ms`);
}
<Profiler id="MyComponent" onRender={onRenderCallback}>
<MyComponent />
</Profiler>
性能监视器
import { PerformanceObserver, performance } from 'perf_hooks';
// 启用性能监视器
if (__DEV__) {
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}ms`);
});
});
observer.observe({ entryTypes: ['measure'] });
}
相关技能
- react-native-components: 构建高性能组件
- react-native-navigation: 优化导航性能
- react-native-native-modules: 原生性能优化