React

State في React — دليل شامل useState 2026

📅 2026-10-13⏱ 9 دقائق قراءة
في المقال السابق، تعلمت المكونات وكيفية تمرير Props. لكن Props **ثابتة** (لا تتغير). الآن سنتعلم **State** — وهي البيانات التي **تتغير** مع تفاعل المستخدم. في هذا الدليل العملي، سنأخذك خطوة بخطوة لفهم `useState` وكيفية إدارة الحالة في React، مع تمارين وحلول. ## ما هو State؟ **State** هي **بيانات متغيرة** داخل المكوّنة. عندما تتغير، React **تُعيد رسم** المكوّنة تلقائياً. **تشبيه بسيط:** تخيل أن State هي **ذاكرة** المكوّنة. الـ Props هي "ما يُعطى لها"، والـ State هي "ما تتذكره". ## الفرق بين Props و State <table> <thead> <tr> <th>المعيار</th> <th>Props</th> <th>State</th> </tr> </thead> <tbody> <tr> <td><strong>المصدر</strong></td> <td>من الأب</td> <td>داخلي</td> </tr> <tr> <td><strong>التغيير</strong></td> <td>❌ لا يتغير</td> <td>✅ يتغير</td> </tr> <tr> <td><strong>الاستخدام</strong></td> <td>بيانات ثابتة</td> <td>بيانات تفاعلية</td> </tr> <tr> <td><strong>المثال</strong></td> <td>اسم المستخدم</td> <td>عدد النقرات</td> </tr> </tbody> </table> ## useState Hook `useState` هو **Hook** يسمح بإضافة State للمكونات الوظيفية. ### الصيغة: ```tsx const [state, setState] = useState(initialValue); ``` **شرح:** - **`state`:** القيمة الحالية. - **`setState`:** دالة لتحديث القيمة. - **`initialValue`:** القيمة الأولية. ### مثال بسيط: ```tsx import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>العدد: {count}</p> <button onClick={() => setCount(count + 1)}>+1</button> </div> ); } ``` **شرح:** 1. `useState(0)` → يبدأ العدد بـ 0. 2. عند الضغط على الزر → `setCount(count + 1)`. 3. React تُحدّث `count` وتُعيد رسم المكوّنة. ## أنواع State ### 1. Number ```tsx const [count, setCount] = useState(0); const [price, setPrice] = useState(99.99); ``` ### 2. String ```tsx const [name, setName] = useState(""); const [email, setEmail] = useState(""); ``` ### 3. Boolean ```tsx const [isOpen, setIsOpen] = useState(false); const [isDark, setIsDark] = useState(true); ``` ### 4. Array ```tsx const [items, setItems] = useState<string[]>([]); const [numbers, setNumbers] = useState<number[]>([1, 2, 3]); ``` ### 5. Object ```tsx const [user, setUser] = useState({ name: "أحمد", age: 25, }); ``` ### 6. Union Types ```tsx type Status = "idle" | "loading" | "success" | "error"; const [status, setStatus] = useState<Status>("idle"); ``` ## تحديث State ### 1. تحديث مباشر ```tsx setCount(10); setName("محمد"); setIsOpen(true); ``` ### 2. تحديث بناءً على القيمة السابقة **❌ خطأ:** ```tsx setCount(count + 1); setCount(count + 1); // لا يعمل! يضيف 1 فقط ``` **✅ صحيح:** ```tsx setCount((prev) => prev + 1); setCount((prev) => prev + 1); // يضيف 2 ``` **السبب:** React تجمّع التحديثات (batching) للأداء. ### 3. تحديث Array **❌ خطأ (لا يعمل):** ```tsx items.push("جديد"); setItems(items); ``` **✅ صحيح:** ```tsx // إضافة setItems([...items, "جديد"]); // حذف setItems(items.filter((item) => item !== "جديد")); // تعديل setItems(items.map((item) => (item === "قديم" ? "جديد" : item))); ``` ### 4. تحديث Object **❌ خطأ:** ```tsx user.name = "محمد"; setUser(user); ``` **✅ صحيح:** ```tsx setUser({ ...user, name: "محمد" }); ``` ## مثال عملي: تطبيق عداد ```tsx import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); const increment = () => setCount((prev) => prev + 1); const decrement = () => setCount((prev) => prev - 1); const reset = () => setCount(0); return ( <div className="counter"> <h2>العدد: {count}</h2> <div className="buttons"> <button onClick={decrement}>-</button> <button onClick={reset}>إعادة</button> <button onClick={increment}>+</button> </div> </div> ); } export default Counter; ``` ## مثال عملي: نموذج إدخال ```tsx import { useState } from "react"; function Form() { const [name, setName] = useState(""); const [email, setEmail] = useState(""); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); alert(`الاسم: ${name}\nالبريد: ${email}`); }; return ( <form onSubmit={handleSubmit}> <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="الاسم" /> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="البريد الإلكتروني" /> <button type="submit">إرسال</button> </form> ); } ``` ## مثال عملي: قائمة مهام ```tsx import { useState } from "react"; interface Todo { id: number; text: string; completed: boolean; } function TodoApp() { const [todos, setTodos] = useState<Todo[]>([]); const [input, setInput] = useState(""); const addTodo = () => { if (input.trim() === "") return; setTodos([ ...todos, { id: Date.now(), text: input, completed: false }, ]); setInput(""); }; const toggleTodo = (id: number) => { setTodos( todos.map((todo) => todo.id === id ? { ...todo, completed: !todo.completed } : todo ) ); }; const deleteTodo = (id: number) => { setTodos(todos.filter((todo) => todo.id !== id)); }; return ( <div className="todo-app"> <h1>📝 قائمة المهام</h1> <div className="input-group"> <input type="text" value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && addTodo()} placeholder="أضف مهمة..." /> <button onClick={addTodo}>إضافة</button> </div> <ul> {todos.map((todo) => ( <li key={todo.id}> <input type="checkbox" checked={todo.completed} onChange={() => toggleTodo(todo.id)} /> <span style={{ textDecoration: todo.completed ? "line-through" : "none" }}> {todo.text} </span> <button onClick={() => deleteTodo(todo.id)}>🗑️</button> </li> ))} </ul> </div> ); } ``` ## State مع TypeScript ### 1. State بسيط ```tsx const [count, setCount] = useState<number>(0); const [name, setName] = useState<string>(""); const [isOpen, setIsOpen] = useState<boolean>(false); ``` ### 2. State مع Union ```tsx type Status = "idle" | "loading" | "success" | "error"; const [status, setStatus] = useState<Status>("idle"); ``` ### 3. State مع Array ```tsx interface Todo { id: number; text: string; } const [todos, setTodos] = useState<Todo[]>([]); ``` ### 4. State مع Object ```tsx interface User { name: string; age: number; } const [user, setUser] = useState<User>({ name: "", age: 0 }); ``` ### 5. State مع Null ```tsx const [user, setUser] = useState<User | null>(null); ``` ## Lazy Initial State إذا كانت القيمة الأولية تحتاج حساباً: ```tsx // ❌ بطيء (يُحسب في كل render): const [data, setData] = useState(expensiveCalculation()); // ✅ سريع (يُحسب مرة واحدة): const [data, setData] = useState(() => expensiveCalculation()); ``` ## رفع الحالة (Lifting State Up) عندما تحتاج مكونتان مشاركة State، ارفعه للمكوّن الأب. **مثال:** ```tsx // المكوّن الأب function Parent() { const [count, setCount] = useState(0); return ( <div> <Child1 count={count} /> <Child2 count={count} setCount={setCount} /> </div> ); } function Child1({ count }: { count: number }) { return <p>العدد: {count}</p>; } function Child2({ count, setCount }: { count: number; setCount: (n: number) => void }) { return <button onClick={() => setCount(count + 1)}>+1</button>; } ``` ## تمارين عملية ### تمرين 1: عداد بسيط أنشئ عداداً مع زر +1 و -1. **الحل:** ```tsx function Counter() { const [count, setCount] = useState(0); return ( <div> <p>{count}</p> <button onClick={() => setCount(count + 1)}>+</button> <button onClick={() => setCount(count - 1)}>-</button> </div> ); } ``` ### تمرين 2: نموذج تسجيل أنشئ نموذجاً بحقول: الاسم، البريد، كلمة المرور. **الحل:** ```tsx function RegisterForm() { const [form, setForm] = useState({ name: "", email: "", password: "" }); const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { setForm({ ...form, [e.target.name]: e.target.value }); }; return ( <form> <input name="name" value={form.name} onChange={handleChange} /> <input name="email" value={form.email} onChange={handleChange} /> <input name="password" type="password" value={form.password} onChange={handleChange} /> </form> ); } ``` ### تمرين 3: Toggle (زر تبديل) أنشئ زراً يبدّل بين "مفعّل" و "معطّل". **الحل:** ```tsx function Toggle() { const [isOn, setIsOn] = useState(false); return ( <button onClick={() => setIsOn(!isOn)}> {isOn ? "✅ مفعّل" : "❌ معطّل"} </button> ); } ``` ### تمرين 4: قائمة تسوق أنشئ قائمة تسوق مع إضافة وحذف. **الحل:** ```tsx function ShoppingList() { const [items, setItems] = useState<string[]>([]); const [input, setInput] = useState(""); const add = () => { if (input) { setItems([...items, input]); setInput(""); } }; return ( <div> <input value={input} onChange={(e) => setInput(e.target.value)} /> <button onClick={add}>إضافة</button> <ul> {items.map((item, i) => ( <li key={i}> {item} <button onClick={() => setItems(items.filter((_, j) => j !== i))}>❌</button> </li> ))} </ul> </div> ); } ``` ### تمرين 5: تبديل اللون أنشئ زراً يبدّل لون خلفية بين الأبيض والأسود. **الحل:** ```tsx function ColorToggle() { const [isDark, setIsDark] = useState(false); return ( <div style={{ background: isDark ? "#000" : "#fff", color: isDark ? "#fff" : "#000", padding: 40 }}> <button onClick={() => setIsDark(!isDark)}> {isDark ? "☀️ فاتح" : "🌙 داكن"} </button> </div> ); } ``` ### تمرين 6: عداد مع حد أقصى أنشئ عداداً لا يزيد عن 10. **الحل:** ```tsx function LimitedCounter() { const [count, setCount] = useState(0); return ( <div> <p>{count}</p> <button onClick={() => setCount(Math.min(10, count + 1))}>+</button> <button onClick={() => setCount(Math.max(0, count - 1))}>-</button> </div> ); } ``` ### تمرين 7: نموذج معاينة مباشرة أنشئ نموذجاً يعرض النص أثناء الكتابة. **الحل:** ```tsx function LivePreview() { const [text, setText] = useState(""); return ( <div> <input value={text} onChange={(e) => setText(e.target.value)} /> <p>المعاينة: {text}</p> </div> ); } ``` ### تمرين 8: قائمة مهام كاملة أنشئ قائمة مهام مع إضافة، حذف، وتعليم كمكتمل. **الحل:** ```tsx interface Todo { id: number; text: string; completed: boolean; } function TodoList() { const [todos, setTodos] = useState<Todo[]>([]); const [input, setInput] = useState(""); const add = () => { if (input.trim()) { setTodos([...todos, { id: Date.now(), text: input, completed: false }]); setInput(""); } }; return ( <div> <input value={input} onChange={(e) => setInput(e.target.value)} /> <button onClick={add}>إضافة</button> <ul> {todos.map((t) => ( <li key={t.id}> <input type="checkbox" checked={t.completed} onChange={() => setTodos(todos.map((x) => (x.id === t.id ? { ...x, completed: !x.completed } : x))) } /> <span style={{ textDecoration: t.completed ? "line-through" : "none" }}>{t.text}</span> <button onClick={() => setTodos(todos.filter((x) => x.id !== t.id))}>🗑️</button> </li> ))} </ul> </div> ); } ``` ## حل المشاكل الشائعة ### 🔴 المشكلة 1: State لا يتحدّث **السبب:** تحديث مباشر بدلاً من دالة التحديث. **الحل:** ```tsx setCount((prev) => prev + 1); ``` ### 🔴 المشكلة 2: Array لا يتحدّث **السبب:** استخدام `push` بدلاً من spread. **الحل:** ```tsx setItems([...items, newItem]); ``` ### 🔴 المشكلة 3: Object لا يتحدّث **السبب:** تعديل مباشر. **الحل:** ```tsx setUser({ ...user, name: "محمد" }); ``` ### 🔴 المشكلة 4: حلقة لا نهائية **السبب:** استدعاء `setState` داخل render. **الحل:** استخدم `useEffect` (سنتعلمه لاحقاً). ## جدول أوامر useState <table> <thead> <tr> <th>الأمر</th> <th>الوظيفة</th> </tr> </thead> <tbody> <tr> <td><code>useState(initial)</code></td> <td>تعريف State</td> </tr> <tr> <td><code>setState(value)</code></td> <td>تعيين قيمة</td> </tr> <tr> <td><code>setState(prev =&gt; ...)</code></td> <td>تحديث بناءً على السابق</td> </tr> <tr> <td><code>useState(() =&gt; ...)</code></td> <td>Lazy initial state</td> </tr> </tbody> </table> ## قائمة تحقق نهائية <table> <thead> <tr> <th>المهمة</th> <th>الحالة</th> </tr> </thead> <tbody> <tr> <td>فهم State و useState</td> <td>⬜</td> </tr> <tr> <td>الفرق بين Props و State</td> <td>⬜</td> </tr> <tr> <td>تحديث State بشكل صحيح</td> <td>⬜</td> </tr> <tr> <td>State مع Array و Object</td> <td>⬜</td> </tr> <tr> <td>State مع TypeScript</td> <td>⬜</td> </tr> <tr> <td>بناء قائمة مهام</td> <td>⬜</td> </tr> <tr> <td>حل التمارين الثمانية</td> <td>⬜</td> </tr> </tbody> </table> ## ماذا بعد هذا المقال؟ الآن بعد أن أتقنت State، أنت جاهز للمقال التالي: 1. **الأحداث (Events)** — التعامل مع تفاعل المستخدم. 2. **النماذج (Forms)** — إدارة المدخلات. 3. **useEffect** — التأثيرات الجانبية. ## الخلاصة في هذا المقال، تعلمت: - ✅ ما هو State ولماذا نحتاجه. - ✅ الفرق بين Props و State. - ✅ `useState` Hook وكيفية استخدامه. - ✅ تحديث State بشكل صحيح. - ✅ State مع Array و Object. - ✅ رفع الحالة (Lifting State Up). - ✅ حل 8 تمارين عملية. **تذكر:** State هو ما يجعل تطبيقات React **تفاعلية**. أتقنه جيداً. **هل أتقنت State؟ شاركنا في التعليقات!**