React

الأحداث والنماذج في React — دليل شامل 2026

📅 2026-10-14⏱ 9 دقائق قراءة
في المقال السابق، تعلمت State وكيفية إدارة البيانات المتغيرة. الآن سنتعلم **الأحداث (Events)** و **النماذج (Forms)** — وهي الطريقة التي يتفاعل بها المستخدم مع تطبيقك. في هذا الدليل العملي، سنأخذك خطوة بخطوة لفهم الأحداث والنماذج في React، مع تمارين وحلول. ## ما هي الأحداث؟ **الأحداث (Events)** هي **تفاعلات المستخدم** مع الصفحة: - النقر (click). - الكتابة (input). - الإرسال (submit). - المرور (mouseover). - الضغط على المفاتيح (keydown). **الفرق بين HTML و React:** <table> <thead> <tr> <th>HTML</th> <th>React</th> </tr> </thead> <tbody> <tr> <td><code>onclick="..."</code></td> <td><code>onClick={...}</code></td> </tr> <tr> <td>أحرف صغيرة</td> <td>camelCase</td> </tr> <tr> <td>نص (string)</td> <td>دالة (function)</td> </tr> </tbody> </table> ## الأحداث الشائعة <table> <thead> <tr> <th>الحدث</th> <th>الوصف</th> </tr> </thead> <tbody> <tr> <td><code>onClick</code></td> <td>نقر بالفأرة</td> </tr> <tr> <td><code>onDoubleClick</code></td> <td>نقر مزدوج</td> </tr> <tr> <td><code>onChange</code></td> <td>تغيير في حقل إدخال</td> </tr> <tr> <td><code>onSubmit</code></td> <td>إرسال نموذج</td> </tr> <tr> <td><code>onFocus</code></td> <td>تركيز على حقل</td> </tr> <tr> <td><code>onBlur</code></td> <td>خروج من حقل</td> </tr> <tr> <td><code>onKeyDown</code></td> <td>ضغط مفتاح</td> </tr> <tr> <td><code>onKeyUp</code></td> <td>رفع مفتاح</td> </tr> <tr> <td><code>onMouseEnter</code></td> <td>دخول الفأرة</td> </tr> <tr> <td><code>onMouseLeave</code></td> <td>خروج الفأرة</td> </tr> </tbody> </table> ## أحداث النقر (onClick) ### 1. دالة بسيطة ```tsx function Button() { const handleClick = () => { alert("تم النقر!"); }; return <button onClick={handleClick}>اضغط</button>; } ``` ### 2. دالة سهمية مباشرة ```tsx <button onClick={() => alert("تم النقر!")}>اضغط</button> ``` **⚠️ ملاحظة:** `onClick={handleClick}` بدون `()` — تمرر الدالة، لا تستدعيها. ### 3. تمرير معاملات ```tsx function Button() { const handleClick = (name: string) => { alert(`مرحباً ${name}`); }; return ( <button onClick={() => handleClick("أحمد")}> اضغط </button> ); } ``` ## أحداث الإدخال (onChange) ### 1. حقل بسيط ```tsx function Input() { const [value, setValue] = useState(""); return ( <input type="text" value={value} onChange={(e) => setValue(e.target.value)} /> ); } ``` **شرح:** - **`value={value}`:** القيمة الحالية (Controlled Component). - **`onChange`:** يُحدّث `value` عند الكتابة. ### 2. عدة حقول ```tsx function Form() { const [form, setForm] = useState({ name: "", email: "", age: 0, }); const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const { name, value, type } = e.target; setForm({ ...form, [name]: type === "number" ? Number(value) : value, }); }; return ( <form> <input name="name" value={form.name} onChange={handleChange} /> <input name="email" value={form.email} onChange={handleChange} /> <input name="age" type="number" value={form.age} onChange={handleChange} /> </form> ); } ``` ## النماذج (Forms) ### 1. النموذج البسيط ```tsx function LoginForm() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // منع السلوك الافتراضي console.log("Email:", email); console.log("Password:", password); }; return ( <form onSubmit={handleSubmit}> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="البريد الإلكتروني" /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="كلمة المرور" /> <button type="submit">تسجيل الدخول</button> </form> ); } ``` **⚠️ مهم:** `e.preventDefault()` يمنع إعادة تحميل الصفحة. ## أنواع المدخلات ### 1. Text ```tsx <input type="text" value={name} onChange={(e) => setName(e.target.value)} /> ``` ### 2. Email ```tsx <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} /> ``` ### 3. Password ```tsx <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} /> ``` ### 4. Number ```tsx <input type="number" value={age} onChange={(e) => setAge(Number(e.target.value))} /> ``` ### 5. Checkbox ```tsx <input type="checkbox" checked={isChecked} onChange={(e) => setIsChecked(e.target.checked)} /> ``` ### 6. Radio ```tsx <input type="radio" name="gender" value="male" checked={gender === "male"} onChange={(e) => setGender(e.target.value)} /> ``` ### 7. Select ```tsx <select value={country} onChange={(e) => setCountry(e.target.value)}> <option value="">اختر</option> <option value="jo">الأردن</option> <option value="eg">مصر</option> <option value="sa">السعودية</option> </select> ``` ### 8. Textarea ```tsx <textarea value={message} onChange={(e) => setMessage(e.target.value)} /> ``` ## Controlled vs Uncontrolled ### Controlled Components (موصى به) ```tsx const [value, setValue] = useState(""); <input value={value} onChange={(e) => setValue(e.target.value)} /> ``` **المميزات:** - ✅ React يتحكم بالقيمة. - ✅ يمكن التحقق من المدخلات. - ✅ يمكن تصفير الحقل بسهولة. ### Uncontrolled Components ```tsx const inputRef = useRef<HTMLInputElement>(null); <input ref={inputRef} defaultValue="" /> // للقراءة: inputRef.current?.value ``` **المميزات:** - ✅ أبسط للحالات البسيطة. - ❌ لا يمكن التحقق أثناء الكتابة. **القاعدة:** استخدم **Controlled** دائماً. ## نموذج كامل: التسجيل ```tsx function RegisterForm() { const [form, setForm] = useState({ name: "", email: "", password: "", confirmPassword: "", agree: false, }); const [errors, setErrors] = useState<Record<string, string>>({}); const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const { name, value, type, checked } = e.target; setForm({ ...form, [name]: type === "checkbox" ? checked : value, }); }; const validate = () => { const newErrors: Record<string, string> = {}; if (form.name.length < 2) { newErrors.name = "الاسم قصير جداً"; } if (!form.email.includes("@")) { newErrors.email = "البريد غير صحيح"; } if (form.password.length < 6) { newErrors.password = "كلمة المرور قصيرة"; } if (form.password !== form.confirmPassword) { newErrors.confirmPassword = "كلمتا المرور غير متطابقتين"; } if (!form.agree) { newErrors.agree = "يجب الموافقة على الشروط"; } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (validate()) { alert("تم التسجيل بنجاح!"); } }; return ( <form onSubmit={handleSubmit}> <div> <input name="name" value={form.name} onChange={handleChange} placeholder="الاسم" /> {errors.name && <span className="error">{errors.name}</span>} </div> <div> <input name="email" type="email" value={form.email} onChange={handleChange} placeholder="البريد الإلكتروني" /> {errors.email && <span className="error">{errors.email}</span>} </div> <div> <input name="password" type="password" value={form.password} onChange={handleChange} placeholder="كلمة المرور" /> {errors.password && <span className="error">{errors.password}</span>} </div> <div> <input name="confirmPassword" type="password" value={form.confirmPassword} onChange={handleChange} placeholder="تأكيد كلمة المرور" /> {errors.confirmPassword && ( <span className="error">{errors.confirmPassword}</span> )} </div> <label> <input name="agree" type="checkbox" checked={form.agree} onChange={handleChange} /> أوافق على الشروط </label> {errors.agree && <span className="error">{errors.agree}</span>} <button type="submit">تسجيل</button> </form> ); } ``` ## أحداث المفاتيح ```tsx function SearchInput() { const [query, setQuery] = useState(""); const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter") { alert(`بحث عن: ${query}`); } if (e.key === "Escape") { setQuery(""); } }; return ( <input value={query} onChange={(e) => setQuery(e.target.value)} onKeyDown={handleKeyDown} placeholder="ابحث واضغط Enter" /> ); } ``` ## أحداث الفأرة ```tsx function HoverCard() { const [isHovered, setIsHovered] = useState(false); return ( <div onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} style={{ background: isHovered ? "#3b82f6" : "#e5e7eb", color: isHovered ? "white" : "black", padding: 20, }} > {isHovered ? "🎉 أنت فوق البطاقة!" : "مرر الفأرة"} </div> ); } ``` ## تمارين عملية ### تمرين 1: زر بسيط أنشئ زراً يزيد عداداً عند الضغط. **الحل:** ```tsx function Button() { const [count, setCount] = useState(0); return <button onClick={() => setCount(count + 1)}>نقرات: {count}</button>; } ``` ### تمرين 2: نموذج بسيط أنشئ نموذجاً بحقل اسم وزر إرسال. **الحل:** ```tsx function NameForm() { const [name, setName] = useState(""); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); alert(`مرحباً ${name}`); }; return ( <form onSubmit={handleSubmit}> <input value={name} onChange={(e) => setName(e.target.value)} /> <button type="submit">إرسال</button> </form> ); } ``` ### تمرين 3: نموذج تسجيل دخول أنشئ نموذجاً بحقل بريد وكلمة مرور. **الحل:** ```tsx function LoginForm() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); console.log({ email, password }); }; return ( <form onSubmit={handleSubmit}> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} /> <button type="submit">دخول</button> </form> ); } ``` ### تمرين 4: checkbox أنشئ checkbox يعرض "مفعّل" أو "معطّل". **الحل:** ```tsx function Checkbox() { const [checked, setChecked] = useState(false); return ( <label> <input type="checkbox" checked={checked} onChange={(e) => setChecked(e.target.checked)} /> {checked ? "مفعّل" : "معطّل"} </label> ); } ``` ### تمرين 5: select أنشئ select لاختيار مدينة. **الحل:** ```tsx function CitySelect() { const [city, setCity] = useState(""); return ( <div> <select value={city} onChange={(e) => setCity(e.target.value)}> <option value="">اختر مدينة</option> <option value="amman">عمّان</option> <option value="cairo">القاهرة</option> <option value="riyadh">الرياض</option> </select> {city && <p>اخترت: {city}</p>} </div> ); } ``` ### تمرين 6: بحث فوري أنشئ حقل بحث يعرض النص أثناء الكتابة. **الحل:** ```tsx function LiveSearch() { const [query, setQuery] = useState(""); const items = ["React", "Vue", "Angular", "Svelte"]; const filtered = items.filter((item) => item.toLowerCase().includes(query.toLowerCase()) ); return ( <div> <input value={query} onChange={(e) => setQuery(e.target.value)} /> <ul> {filtered.map((item) => ( <li key={item}>{item}</li> ))} </ul> </div> ); } ``` ### تمرين 7: نموذج مع تحقق أنشئ نموذجاً يتحقق من أن البريد يحتوي على `@`. **الحل:** ```tsx function EmailForm() { const [email, setEmail] = useState(""); const [error, setError] = useState(""); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!email.includes("@")) { setError("البريد غير صحيح"); return; } alert("تم!"); }; return ( <form onSubmit={handleSubmit}> <input value={email} onChange={(e) => setEmail(e.target.value)} /> {error && <p style={{ color: "red" }}>{error}</p>} <button type="submit">إرسال</button> </form> ); } ``` ### تمرين 8: نموذج تسجيل كامل أنشئ نموذجاً بحقول: اسم، بريد، كلمة مرور، مع تحقق. **الحل:** ```tsx function FullForm() { const [form, setForm] = useState({ name: "", email: "", password: "" }); const [errors, setErrors] = useState<Record<string, string>>({}); const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { setForm({ ...form, [e.target.name]: e.target.value }); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const newErrors: Record<string, string> = {}; if (form.name.length < 2) newErrors.name = "الاسم قصير"; if (!form.email.includes("@")) newErrors.email = "البريد غير صحيح"; if (form.password.length < 6) newErrors.password = "كلمة المرور قصيرة"; setErrors(newErrors); if (Object.keys(newErrors).length === 0) { alert("تم بنجاح!"); } }; return ( <form onSubmit={handleSubmit}> <div> <input name="name" value={form.name} onChange={handleChange} placeholder="الاسم" /> {errors.name && <p style={{ color: "red" }}>{errors.name}</p>} </div> <div> <input name="email" value={form.email} onChange={handleChange} placeholder="البريد" /> {errors.email && <p style={{ color: "red" }}>{errors.email}</p>} </div> <div> <input name="password" type="password" value={form.password} onChange={handleChange} placeholder="كلمة المرور" /> {errors.password && <p style={{ color: "red" }}>{errors.password}</p>} </div> <button type="submit">تسجيل</button> </form> ); } ``` ## حل المشاكل الشائعة ### 🔴 المشكلة 1: النموذج يعيد تحميل الصفحة **السبب:** لم تستخدم `e.preventDefault()`. **الحل:** ```tsx const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // ... }; ``` ### 🔴 المشكلة 2: `Cannot read property 'value' of undefined` **السبب:** لم تضف `value` أو `onChange`. **الحل:** ```tsx <input value={value} onChange={(e) => setValue(e.target.value)} /> ``` ### 🔴 المشكلة 3: `You provided a 'value' prop without 'onChange'` **السبب:** `value` بدون `onChange` (حقل للقراءة فقط). **الحل:** أضف `onChange` أو `readOnly`. ### 🔴 المشكلة 4: `A component is changing an uncontrolled input to be controlled` **السبب:** `value` يبدأ بـ `undefined`. **الحل:** ```tsx const [value, setValue] = useState(""); // ← قيمة أولية ``` ## جدول الأحداث <table> <thead> <tr> <th>الحدث</th> <th>النوع</th> <th>الاستخدام</th> </tr> </thead> <tbody> <tr> <td><code>onClick</code></td> <td>MouseEvent</td> <td>أزرار</td> </tr> <tr> <td><code>onChange</code></td> <td>ChangeEvent</td> <td>حقول الإدخال</td> </tr> <tr> <td><code>onSubmit</code></td> <td>FormEvent</td> <td>النماذج</td> </tr> <tr> <td><code>onKeyDown</code></td> <td>KeyboardEvent</td> <td>لوحة المفاتيح</td> </tr> <tr> <td><code>onMouseEnter</code></td> <td>MouseEvent</td> <td>المرور</td> </tr> <tr> <td><code>onFocus</code></td> <td>FocusEvent</td> <td>التركيز</td> </tr> <tr> <td><code>onBlur</code></td> <td>FocusEvent</td> <td>الخروج</td> </tr> </tbody> </table> ## قائمة تحقق نهائية <table> <thead> <tr> <th>المهمة</th> <th>الحالة</th> </tr> </thead> <tbody> <tr> <td>فهم الأحداث في React</td> <td>⬜</td> </tr> <tr> <td>استخدام onClick</td> <td>⬜</td> </tr> <tr> <td>استخدام onChange</td> <td>⬜</td> </tr> <tr> <td>بناء نماذج كاملة</td> <td>⬜</td> </tr> <tr> <td>التحقق من المدخلات</td> <td>⬜</td> </tr> <tr> <td>Controlled Components</td> <td>⬜</td> </tr> <tr> <td>حل التمارين الثمانية</td> <td>⬜</td> </tr> </tbody> </table> ## ماذا بعد هذا المقال؟ الآن بعد أن أتقنت الأحداث والنماذج، أنت جاهز للمقال التالي: 1. **useEffect** — التأثيرات الجانبية. 2. **القوائم والشروط** — العرض الديناميكي. 3. **React Router** — التنقل بين الصفحات. ## الخلاصة في هذا المقال، تعلمت: - ✅ الأحداث في React (onClick, onChange, onSubmit). - ✅ بناء النماذج (Forms). - ✅ جميع أنواع المدخلات (input, select, checkbox, radio). - ✅ التحقق من المدخلات (Validation). - ✅ Controlled vs Uncontrolled Components. - ✅ أحداث المفاتيح والفأرة. - ✅ حل 8 تمارين عملية. **تذكر:** الأحداث والنماذج هي ما يجعل التطبيق تفاعلياً. أتقنها جيداً. **هل أتقنت الأحداث والنماذج؟ شاركنا في التعليقات!**