الخطوة 4 في تطبيق الجوال: إدارة الحالة
أدر حالات التحميل والأخطاء وتحديثات الرسائل على نحو سليم.
ما ستتعلمه
- عدة متغيرات حالة لتمثيل حالات مختلفة في واجهة المستخدم
- تحديثات تفاؤلية في واجهة المستخدم
- مؤشرات التحميل
- عرض رسائل الخطأ
الخطوة 1: إضافة متغيرات الحالة
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
ثلاثة أنواع من الحالة:
- البيانات: messages — محتوى الدردشة
- واجهة المستخدم: loading — ما إذا كان هناك طلب قيد التنفيذ
- الخطأ: error — رسالة خطأ يراها المستخدم
الخطوة 2: مسار الإرسال
1. يكتب المستخدم الرسالة ويضغط إرسال
2. إفراغ حقل الإدخال فورًا وإظهار مؤشر التحميل
3. إضافة الرسالة إلى القائمة تفاؤليًا
4. إرسال الطلب إلى الواجهة الخلفية
5a. النجاح → تحديث الرسالة باستجابة الخادم + إضافة رد الذكاء الاصطناعي
5b. الفشل → تعليم الرسالة بأنها فشلت، وإظهار الخطأ
6. إخفاء مؤشر التحميل
الخطوة 3: تعطيل الإرسال أثناء التحميل
<TouchableOpacity
style={[styles.sendButton, loading && styles.sendButtonDisabled]}
onPress={handleSend}
disabled={loading}
>
<Text style={styles.sendButtonText}>Send</Text>
</TouchableOpacity>
الخطوة 4: عرض شريط الخطأ
{error && (
<View style={styles.errorBanner}>
<Text style={styles.errorText}>Error: {error}</Text>
<TouchableOpacity onPress={() => setError(null)}>
<Text style={styles.errorDismiss}>X</Text>
</TouchableOpacity>
</View>
)}
الأنماط:
errorBanner: {
backgroundColor: "#FFE0E0",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
padding: 10,
},
errorText: { color: "#D00", flex: 1 },
errorDismiss: { color: "#D00", fontWeight: "bold", marginLeft: 10, fontSize: 18 },
الخطوة 5: إضافة ترويسة
<View style={styles.header}>
<Text style={styles.headerTitle}>Agentic Chat</Text>
</View>
الأنماط:
header: {
backgroundColor: "#007AFF",
paddingTop: 50,
paddingBottom: 15,
paddingHorizontal: 16,
},
headerTitle: { color: "#FFF", fontSize: 20, fontWeight: "bold" },
الخطوة 6: التعامل مع لوحة المفاتيح
import { KeyboardAvoidingView, Platform } from "react-native";
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === "ios" ? "padding" : "height"}
>
{/* everything */}
</KeyboardAvoidingView>
هذا يدفع صف الإدخال إلى الأعلى عند فتح لوحة المفاتيح بدلًا من أن يغطيه.
الخطوة 7: فهم تحديثات useState
// ❌ خطأ — لا يعمل بموثوقية مع FlatList
messages.push(newMessage);
setMessages(messages);
// ✅ صحيح — ينشئ مصفوفة جديدة
setMessages([...messages, newMessage]);
// ✅ صحيح — يستخدم الحالة السابقة
setMessages((prev) => [...prev, newMessage]);
أنشئ دائمًا مصفوفة أو كائنًا جديدًا بدلًا من تعديل الموجود. تكتشف React التغييرات عبر المرجع، فتحتاج إلى مرجع جديد لتعرف أن عليها إعادة العرض.
الخطوة 8: اختبار المسار الكامل
- إرسال رسالة → يُفرَّغ حقل الإدخال ويظهر مؤشر التحميل
- انتظار الاستجابة → تظهر الرسالة ورد الذكاء الاصطناعي
- إحداث خطأ في الشبكة (أوقف الواجهة الخلفية) → يظهر شريط الخطأ وتُعلَّم الرسالة بأنها فشلت
- إغلاق الخطأ → يختفي الشريط