قياس الأداء وتقليل البطء
اكتشف البطء بالقياس وعالجه بالأدوات الصحيحة. ⏱ نحو 40 دقيقة.
- تعدّد أسباب البطء الشائعة وعلاجها.
- تعرض قوائم كبيرة بكفاءة بـ
FlatList. - تقيس الأداء (عدّ الرسمات) قبل التحسين.
١البطء عدوّ التجربة
الأجهزة المحمولة أضعف من الحواسيب، وبطء الواجهة (تلعثم التمرير، تأخّر اللمس) يطرد المستخدمين. الناتج الرابع للمقرر يطلب قياس الأداء وتحسينه. أسباب البطء الشائعة:
| السبب | الأثر | العلاج |
|---|---|---|
| رسم قائمةٍ ضخمة كاملة | ذاكرة وبطء | FlatList (نافذة مرئيّة) |
| عملٌ ثقيل في كل رسم | تجمّد | useMemo (الدرس 24) |
| إعادة رسمٍ لا لزوم لها | استهلاك | React.memo (الدرس 24) |
| صورٌ ضخمة | بطء تحميل | أحجامٌ مناسبة وتخزين مؤقت |
٢قائمةٌ كبيرة بكفاءة
FlatList لا يرسم إلّا المرئيّ. هذه قائمةٌ من 200 عنصرٍ تبقى سلسةً لأنها لا تُرسم كاملة:
import { View, Text, FlatList, StyleSheet } from 'react-native'; const DATA = Array.from({ length: 200 }, (_, i) => ({ id: String(i), n: i + 1 })); export default function App() { return ( <View style={{ height: 240 }}> <Text style={styles.h}>200 عنصرًا — مرئيُّها فقط يُرسَم</Text> <FlatList data={DATA} keyExtractor={(it) => it.id} initialNumToRender={10} renderItem={({ item }) => ( <Text style={styles.row}>الصفّ رقم {item.n}</Text> )} /> </View> );} const styles = StyleSheet.create({ h: { fontWeight: 'bold', padding: 10, color: '#E8820C' }, row: { padding: 12, borderBottomWidth: 1, borderColor: '#eee' },});
initialNumToRender يحدّد كم عنصرًا يُرسم أولًا. مرّر القائمة: العناصر تُنشأ عند الحاجة لا دفعةً واحدة.
٣قياس بسيط: عدّ الرسمات
«ما لا يُقاس لا يُحسَّن». طريقةٌ بسيطة: عدّاد رسماتٍ بـ useRef يطبع في Console كم مرّةً أُعيد رسم المكوّن. افتح Console وراقب:
import { useState, useRef } from 'react';import { View, Text, Pressable, StyleSheet } from 'react-native'; export default function App() { const [n, setN] = useState(0); const renders = useRef(0); renders.current += 1; console.log('عدد مرّات الرسم:', renders.current); return ( <View style={styles.box}> <Text style={styles.t}>القيمة: {n}</Text> <Text style={styles.r}>رُسِم {renders.current} مرّة</Text> <Pressable style={styles.btn} onPress={() => setN(n + 1)}> <Text style={styles.bt}>زيادة</Text> </Pressable> </View> );} const styles = StyleSheet.create({ box: { padding: 24, alignItems: 'center' }, t: { fontSize: 24, fontWeight: 'bold' }, r: { color: '#888', marginTop: 4 }, btn: { backgroundColor: '#E8820C', padding: 10, borderRadius: 8, marginTop: 12 }, bt: { color: 'white' },});
كل ضغطةٍ تزيد العدّاد والرسمات. في الدرس القادم نقلّل الرسمات غير الضروريّة بـ memo.
توقّع وتحقّق
لماذا FlatList أسرع لقائمةٍ طويلة؟
قاعدة التحسين:
initialNumToRender يحدّد:
عدّاد الرسمات نحفظه بـ:
الخلاصة
- البطء يطرد المستخدمين؛ أسبابه: قوائم ضخمة، عملٌ ثقيل، رسمٌ زائد.
FlatListيرسم المرئيّ فقط؛initialNumToRenderيضبط البداية.- قِس أولًا (عدّ الرسمات) ثم حسّن.
تحدٍّ برمجي: قائمة كبيرة سلسة
متوسطاعرض 50 عنصرًا بـ FlatList.
- أنشئ مصفوفةً من 50 عنصرًا.
- اعرضها بـ
FlatListمعkeyExtractor. <Text testID="head">يعرض العدد 50.
👀 اعرض الناتج المطلوب (وجرّبه)
- الكود يعمل بلا أخطاء في Console
- العنوان يعرض 50
- استُخدم FlatList
- أُنشئت 50 عنصرًا
💡 تلميح 1
Array.from({{ length: 50 }}, …) ينشئ المصفوفة.💡 تلميح 2
حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
import { View, Text, FlatList, StyleSheet } from 'react-native'; const DATA = Array.from({ length: 50 }, (_, i) => ({ id: String(i), n: i + 1 })); export default function App() { return ( <View style={{ height: 240 }}> <Text testID="head" style={styles.h}>العناصر: {DATA.length}</Text> <FlatList data={DATA} keyExtractor={(it) => it.id} renderItem={({ item }) => <Text style={styles.row}>عنصر {item.n}</Text>} /> </View> );} const styles = StyleSheet.create({ h: { fontWeight: 'bold', padding: 10, color: '#E8820C' }, row: { padding: 10, borderBottomWidth: 1, borderColor: '#eee' },});