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 تمارين عملية.
**تذكر:** الأحداث والنماذج هي ما يجعل التطبيق تفاعلياً. أتقنها جيداً.
**هل أتقنت الأحداث والنماذج؟ شاركنا في التعليقات!**