تحسين الأداء — React Native المتقدم
تحسين أداء React Native
1. FlatList Optimization
// ❌ سيء
<FlatList
data={items}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => handlePress(item)}>
<Text>{item.name}</Text>
</TouchableOpacity>
)}
/>
// ✅ جيد
const renderItem = useCallback(({ item }) => (
<ListItem item={item} onPress={handlePress} />
), [handlePress]);
<FlatList
data={items}
renderItem={renderItem}
keyExtractor={(item) => item.id}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews={true}
getItemLayout={(data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
/>
// مكون العنصر مع memo
const ListItem = React.memo(({ item, onPress }) => (
<TouchableOpacity onPress={() => onPress(item)}>
<Text>{item.name}</Text>
</TouchableOpacity>
));2. React.memo للمكونات
// ❌ يُعاد رسمه في كل مرة
const SlowList = ({ data, onUpdate }) => {
return (
<View>
{data.map(item => <Text key={item.id}>{item.name}</Text>)}
</View>
);
};
// ✅ يُعاد رسمه فقط عند تغير props
const MemoList = React.memo(({ data, onUpdate }) => {
return (
<View>
{data.map(item => <Text key={item.id}>{item.name}</Text>)}
</View>
);
});
// مع مقارنة مخصصة
const MemoListByLength = React.memo(
({ data, onUpdate }) => {
// ...
},
(prevProps, nextProps) => {
return prevProps.data.length === nextProps.data.length;
}
);3. useMemo و useCallback
function SearchScreen() {
const [query, setQuery] = useState('');
const [items, setItems] = useState([]);
// ❌ يُحسب في كل render
const filteredSlow = items.filter(item =>
item.name.toLowerCase().includes(query.toLowerCase())
);
// ✅ يُحسب فقط عند تغير items أو query
const filteredItems = useMemo(() => {
return items.filter(item =>
item.name.toLowerCase().includes(query.toLowerCase())
);
}, [items, query]);
// ❌ دالة جديدة في كل render
const handlePressSlow = (item) => {
console.log(item);
};
// ✅ نفس الدالة طالما لم تتغير dependencies
const handlePress = useCallback((item) => {
console.log(item);
}, []);
return (
<FlatList
data={filteredItems}
renderItem={({ item }) => (
<ListItem item={item} onPress={handlePress} />
)}
/>
);
}4. تحسين الصور
npm install expo-imageimport { Image } from 'expo-image';
// بدلاً من Image العادي
<Image
source={{ uri: imageUrl }}
style={{ width: 200, height: 200 }}
contentFit="cover"
transition={200}
cachePolicy="memory-disk"
placeholder={blurhash}
/>
// Blurhash للتحميل
const blurhash = 'L6PZfSi_.AyE_3t7t7R**0o#DgR4';5. تجنب re-renders غير ضرورية
function Row({ item, items, handlePress }) {
// ✅ دالة ثابتة بدل دالة جديدة في كل رسم
const handleItemPress = useCallback(() => handlePress(item), [item, handlePress]);
return (
<>
{/* ❌ سيء: كائن أنماط جديد في كل رسم */}
<View style={{ backgroundColor: 'red', padding: 10 }} />
{/* ✅ جيد: StyleSheet */}
<View style={styles.container} />
{/* ❌ سيء: دالة سهمية جديدة في كل رسم */}
<TouchableOpacity onPress={() => handlePress(item)} />
{/* ✅ جيد */}
<TouchableOpacity onPress={handleItemPress} />
{/* ❌ سيء: بلا key ومكوّن مضمّن */}
{items.map((i) => <View>{i.name}</View>)}
{/* ✅ جيد: مكوّن منفصل مع key */}
{items.map((i) => <ListItem key={i.id} item={i} />)}
</>
);
}6. Hermes Engine (تحسين كبير)
في app.json:
{
"expo": {
"jsEngine": "hermes"
}
}7. قياس الأداء
// قياس وقت التنفيذ
console.time('fetchData');
await fetchData();
console.timeEnd('fetchData');
// React DevTools Profiler
import { Profiler } from 'react';
<Profiler
id="FlatList"
onRender={(id, phase, actualDuration) => {
console.log(`${id} took ${actualDuration}ms`);
}}
>
<FlatList data={items} renderItem={renderItem} />
</Profiler>اختبر فهمك