ما هي الحالة (State)؟
State بيانات تخصّ المكوّن ويمكن أن تتغيّر مع الوقت (مثل عدّاد أو نص حقل إدخال). عند تغيّر الحالة، تُعيد React رسم المكوّن تلقائيًا.
useState
نستخدم الخطّاف useState لتعريف حالة:
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>العدّ: {count}</p>
<button onClick={() => setCount(count + 1)}>زيادة</button>
</div>
);
}
شرح السطر const [count, setCount] = useState(0):
count= القيمة الحالية (تبدأ بـ0).setCount= الدالة الوحيدة المسموح بها لتغيير القيمة.useState(0)= القيمة الابتدائية.
القاعدة الذهبية
⚠️ لا تعدّل الحالة مباشرة! استخدم دائمًا دالة التحديث.
// ❌ خطأ — لن تتحدّث الواجهة
count = count + 1;
// ✅ صحيح
setCount(count + 1);
التحديث بناءً على القيمة السابقة
عند الاعتماد على القيمة الحالية، مرّر دالة:
setCount((prev) => prev + 1);
لماذا يهم هذا؟ count داخل الدالة هي لقطة من العرض الحالي، لا تتغيّر حتى العرض التالي. لذلك:
function handleClick() {
setCount(count + 1); // count = 0 → يطلب 1
setCount(count + 1); // count ما زالت 0 → يطلب 1 مرة أخرى
}
// النتيجة: 1 لا 2
function handleClickFixed() {
setCount((prev) => prev + 1); // 0 → 1
setCount((prev) => prev + 1); // 1 → 2
}
// النتيجة: 2
الكائنات والمصفوفات: أنشئ نسخة جديدة
React يقارن القيمة الجديدة بالقديمة بالمرجع. تعديل المصفوفة نفسها لا يغيّر مرجعها، فلا يرى React أي تغيير ولا يعيد العرض:
const [items, setItems] = useState(["أ"]);
// ❌ نفس المصفوفة بعد تعديلها — لن تتحدّث الواجهة
items.push("ب");
setItems(items);
// ✅ مصفوفة جديدة
setItems([...items, "ب"]);
// ✅ ونفس الفكرة مع الكائنات
const [user, setUser] = useState({ name: "سارة", age: 20 });
setUser({ ...user, age: 21 });
قيمة ابتدائية مكلفة؟ مرّر دالة
القيمة الابتدائية تُستخدم في أول عرض فقط، لكن التعبير نفسه يُحسب في كل عرض. إن كان حسابها مكلفًا، مرّر دالة فيستدعيها React مرة واحدة:
// ❌ تُقرأ من localStorage وتُحلَّل في كل عرض
const [todos, setTodos] = useState(JSON.parse(localStorage.getItem("todos") ?? "[]"));
// ✅ تُنفَّذ مرة واحدة فقط
const [todos, setTodos] = useState(() => JSON.parse(localStorage.getItem("todos") ?? "[]"));
أخطاء شائعة
- تعديل الحالة مباشرة (
count = 5أوitems.push(...)) بدل دالة التحديث. - انتظار القيمة الجديدة فورًا: بعد
setCount(5)مباشرة،countفي نفس الدالة ما زالت القديمة؛ الجديدة تظهر في العرض التالي. setStateبنفس القيمة الحالية: إذا كانت مطابقة للقديمة (Object.is) يتجاهل React التحديث ولا يعيد العرض.
🎯 التالي: التعامل مع الأحداث (Events).