React: معالجة الأحداث
آخر تحديث: 2026-10-26
معالجة الأحداث هي النهايات العصبية لتطبيق React — فعندما ينقر المستخدمون على الأزرار، أو يدخلون نصًا، أو يرسلون نماذج، يتم الرد على هذه التفاعلات من خلال الأحداث. ويُعد نظام الأحداث في React أكثر ذكاءً وتوحيدًا من أحداث DOM الأصلية.
1. ما ستتعلمه
- الفرق بين الأحداث المركبة في React والأحداث الأصلية الأحداث الشائعة: onClick / onChange / onSubmit / onKeyDown
- التعامل مع كائنات الأحداث
- تمرير المعلمات إلى دوال معالجة الأحداث
- منع السلوك الافتراضي وانتشار الأحداث
2. قصة عن التفاعل مع النماذج
(1) نقاط الضعف: 3 عقبات في عملية إرسال النماذج
يعمل بوب على إنشاء نموذج لتسجيل المستخدمين وكتابة معالجات الأحداث بلغة جافا سكريبت الأصلية:
// Native JS:Various compatibility issues and details need to be handled manually
// 1. Get DOM Element
const form = document.getElementById('register-form')
const nameInput = document.getElementById('name')
const submitBtn = document.getElementById('submit-btn')
// 2. Event Binding
form.addEventListener('submit', function(event) {
event.preventDefault() // Prevent the page from refreshing
// 3. Manually Retrieving Form Data
const formData = new FormData(form)
const data = Object.fromEntries(formData)
// 4. Submit Data
fetch('/api/register', {
method: 'POST',
body: JSON.stringify(data)
})
})
// 5. Real-Time Input Validation
nameInput.addEventListener('input', function(event) {
if (event.target.value.length < 2) {
showError('Name (at least) 2 characters')
} else {
hideError()
}
})
// 6. Prevent duplicate submissions when the Submit button is clicked
let isSubmitting = false
submitBtn.addEventListener('click', function() {
if (isSubmitting) return
isSubmitting = true
submitBtn.disabled = true
submitBtn.textContent = 'Submitting......'
})
مشكلة بوب:
- الرمز المتناثر: تنتشر عمليات ربط الأحداث ومعالجة البيانات وتحديثات واجهة المستخدم في مواقع مختلفة
- تسرب الذاكرة: نسيان إزالة مستمعي الأحداث
- مشكلات التوافق: توجد اختلافات بين واجهات برمجة التطبيقات (API) الخاصة بالأحداث في المتصفحات المختلفة
(2) معالجة الأحداث في React
▶ جرّب الكودالمزايا: تم تقليص حجم الكود من 30 سطراً إلى 15 سطراً، دون الحاجة إلى التعديل على DOM، ودون مواجهة أي مشكلات تتعلق بإلغاء ربط الأحداث، ودون أي مشكلات تتعلق بتوافق المتصفحات.
3. الأحداث المركبة في React
أحداث React ليست أحداث DOM أصلية، بل هي SyntheticEvents — حيث يستمع React إليها على المستوى الأعلى ويحاكي نظام أحداث متوافق مع جميع المتصفحات.
| ميزة | أحداث DOM الأصلية | أحداث React المركبة |
|---|---|---|
| طريقة الربط | addEventListener / onclick |
الكتابة مباشرةً بلغة JSX |
| التوافق مع المتصفحات | يلزم التعامل اليدوي مع الاختلافات | التوحيد التلقائي |
| إدارة الذاكرة | يجب إزالة المستمعين يدويًّا | التنظيف التلقائي |
| كائن الحدث | الحدث الأصلي | الحدث الاصطناعي |
| منع تكوّن الفقاعات | event.stopPropagation() |
متطابق (موحد) |
| الحظر الافتراضي | event.preventDefault() |
كما هو (موحد) |
graph TB
A[The user clicks the button] --> B[React Root Node Event Handling]
B --> C[Create a Synthetic Event Object]
C --> D[Simulated Bubbles/Capture Phase]
D --> E[Call JSX Bound to the middle handler]
style B fill:#61dafb,color:#000
style C fill:#1890ff,color:#fff
الناتج:
...
تم النقر على زر "Log In"
تم تمرير مؤشر الفأرة فوق الزر
غادر المؤشر الزر
4. مرجع سريع للأحداث الشائعة
| اسم الحدث | شروط التشغيل | السيناريوهات الشائعة | نوع كائن الحدث |
|---|---|---|---|
onClick |
النقر على عنصر | زر، رابط، بطاقة | MouseEvent |
onChange |
التغييرات في محتوى حقول الإدخال | حقول النماذج، القوائم المنسدلة | ChangeEvent |
onSubmit |
إرسال النموذج | تسجيل الدخول/التسجيل/البحث | FormEvent |
onFocus |
يتم تحديد العنصر | يتم تمييز حقل الإدخال | FocusEvent |
onBlur |
فقد العنصر التركيز | التحقق من صحة المدخلات | FocusEvent |
onKeyDown |
اضغط على أي مفتاح | مفتاح الاختصار، اضغط على Enter للبحث | KeyboardEvent |
onKeyUp |
الأخبار والبيانات الصحفية | البحث في الوقت الفعلي | KeyboardEvent |
onMouseEnter |
التمرير بالماوس | تأثير التمرير | MouseEvent |
onMouseLeave |
عند إبعاد الماوس | تأثير التمرير | MouseEvent |
onScroll |
التمرير | التمرير اللانهائي | UIEvent |
▶ مثال: نظرة عامة شاملة على الأحداث الشائعة
▶ عرض المثال القابل للتشغيل (81 سطرًا)
الناتج:
نموذج تسجيل دخول بالبريد الإلكتروني/كلمة المرور. بريد غير صالح → إطار أحمر + "The email address format is incorrect.". كلمة مرور أقل من 6 محارف → "Password must be at least 6 chars". الإرسال → console.log({email, password})
5. تمرير معلمات الأحداث
(1) تمرير المعلمات مباشرةً
قم بتغليفها في دالة سهمية وقم بتمرير المعلمات الإضافية مباشرةً:
function UserList({ users, onDelete }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>
{user.name}
{/* Arrow Functions:Incoming user.id As an additional parameter */}
<button onClick={() => onDelete(user.id)}>
Delete
</button>
</li>
))}
</ul>
)
}
// Usage
<UserList
users={users}
onDelete={(id) => console.log('Delete User:', id)}
/>
(2) استرداد كلاً من كائن الحدث والمعلمات المخصصة
function ColorPicker({ colors, onSelect }) {
return (
<div>
<p>Select a Color:</p>
{colors.map(color => (
<button
key={color}
onClick={(event) => {
// event:Native Synthesis Event Object
// color:Custom Parameters
onSelect(color)
console.log('Click here:', event.clientX, event.clientY)
}}
style={{
backgroundColor: color,
width: '40px',
height: '40px',
border: '2px solid #ddd',
borderRadius: '50%',
margin: '4px',
cursor: 'pointer'
}}
/>
))}
</div>
)
}
(3) ثلاث طرق لتمرير كائنات الأحداث
| الطريقة | الصيغة | السيناريوهات القابلة للتطبيق |
|---|---|---|
| التمرير الضمني | onClick={handleClick} |
لا توجد معلمات إضافية مطلوبة |
| دوال السهم | onClick={() => handleClick(id)} |
تتطلب معلمات |
| تمرير متزامن | onClick={(e) => handleClick(e, id)} |
يتطلب كائن حدث + معلمات مخصصة |
6. منع السلوك الافتراضي وانتشار التأثير
(1) منع السلوك الافتراضي: preventDefault()
أكثر حالات الاستخدام شيوعًا هي منع تحديث الصفحة عند إرسال نموذج:
▶ جرّب الكود(2) منع تكوّن الفقاعات: stopPropagation()
▶ جرّب الكود
7. مثال كامل: قائمة المهام (معالجة الأحداث الشاملة)
▶ عرض المثال القابل للتشغيل (111 سطرًا)
الناتج:
... ('Log In:', { email, password })
تم النقر على زر "Log In"
تم تمرير مؤشر الفأرة فوق الزر
غادر المؤشر الزر
مسار التفاعل:
- اكتب اسم المهمة في مربع النص، ثم اضغط على مفتاح Enter، أو انقر على زر «إضافة» → تُضاف المهمة إلى القائمة
- حدد مربع الاختيار → ضع علامة على المهمة على أنها مكتملة (يظهر النص مشطوبًا وباللون الرمادي)
- انقر على زر ✕ → احذف المهمة (
stopPropagationلمنع النقر المزدوج من تشغيل وظيفة التحرير)- انقر نقرًا مزدوجًا على أي مهمة → يظهر مربع حوار للتحرير
▶ المثال 2: اختصارات لوحة المفاتيح وإدارة التركيز
▶ عرض المثال القابل للتشغيل (95 سطرًا)
الناتج:
تركيز تلقائي على حقل الإدخال. Ctrl+S → "💾 Saved (Ctrl+S)"، Ctrl+Z → "↩️ Undo (Ctrl+Z)"، Escape → تفريغ، Enter → "✅ Confirm: [text]". يعرض المفاتيح التي ضُغطت.
الناتج:
العنوان الفرعي: "⌨️ Shortcut Keys Panel". يعرض: "⌨️ Shortcut Keys Panel". الإدخال: Type here، Try the shortcut keys.... . يتولى useEffect إدارة الآثار الجانبية. يشير useRef إلى DOM/متغير
▶ المثال 3: التعامل مع أحداث الفرز بالسحب والإفلات
▶ جرّب الكودالناتج:
4 عناصر قابلة للسحب (Apple، Banana، Cherry، Date). السحب لإعادة الترتيب؛ العنصر المسحوب يظهر بإطار مُبرَز بالأزرق.
الناتج:
يعرض: "Drag to Reorder". الحالة: items (setter: setItems)، dragIdx (setter: setDragIdx)
▶ المثال 4: ربط مخصص لتغليف مستمعي الأحداث
▶ جرّب الكودالناتج:
خطاف useEventListener: يضيف/يزيل مستمعي أحداث DOM تلقائيًا. التنظيف عند التفكيك يمنع تسرب الذاكرة
الناتج:
الحالة: pos (setter: setPos). يتولى useEffect إدارة الآثار الجانبية. يُخزن useCallback مرجع دالة المعالجة
▶ المثال 5: إرسال النموذج ودمج الأحداث
function SearchForm({ onSearch }) {
const [query, setQuery] = useState('')
const [category, setCategory] = useState('all')
function handleSubmit(e) {
e.preventDefault()
onSearch({ query, category })
}
function handleReset() {
setQuery('')
setCategory('all')
}
return (
<form onSubmit={handleSubmit} style={{ maxWidth: 400, margin: '0 auto' }}>
<div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
<input value={query} onChange={e => setQuery(e.target.value)}
placeholder="Search..." style={{ flex: 1, padding: 8, borderRadius: 4 }} />
<select value={category} onChange={e => setCategory(e.target.value)}
style={{ padding: 8, borderRadius: 4 }}>
<option value="all">All</option>
<option value="electronics">Electronics</option>
<option value="books">Books</option>
</select>
</div>
<div style={{ display: 'flex', gap: 8 }}>
<button type="submit" style={{ padding: '6px 16px', cursor: 'pointer' }}>Search</button>
<button type="button" onClick={handleReset} style={{ padding: '6px 16px', cursor: 'pointer' }}>Reset</button>
</div>
</form>
)
}
الناتج:
شريط بحث + قائمة منسدلة للتصنيفات (All/Electronics/Books). البحث يُرسل {query, category}. إعادة الضبط تفرغ الحقلين.
❓ أسئلة شائعة
() => handleClick(id) بدلاً من handleClick(id) فقط؟onClick={handleClick(id)} مباشرةً، فسوف يقوم React بتنفيذ handleClick(id) فورًا أثناء عملية العرض، بدلاً من الانتظار حتى يتم النقر عليها. وذلك لأنها استدعاء دالة (مع أقواس)، وليست إشارة إلى دالة (بدون أقواس). الطريقة الصحيحة هي onClick={() => handleClick(id)} (دالة السهم مع التنفيذ المؤجل) أو onClick={handleClick} (الإشارة المباشرة إلى اسم الدالة عند عدم تمرير أي معلمات).onClick مباشرةً. الحلول: ① استدعاء عدة دوال onClick={() => { fn1(); fn2() }} داخل نفس معالج الأحداث؛ ② أو تغليف العنصر بعدة HOCs. عادةً، لا يحتاج العنصر سوى إلى معالج أحداث واحد، يمكنك من خلاله استدعاء عدة أجزاء من المنطق.SyntheticEvent في React هو غلاف متعدد المتصفحات للأحداث الأصلية، يوفر واجهة برمجة تطبيقات موحدة (مثل e.preventDefault() وe.stopPropagation()) ويعمل بشكل متسق عبر جميع المتصفحات. تعمل الأحداث الاصطناعية في إطار آلية تفويض الأحداث — حيث يتم ربط جميع الأحداث بالعقدة الجذرية بدلاً من عناصر DOM الفردية. في React 17 والإصدارات الأحدث، يتم تفويض الأحداث إلى العقدة الجذرية بدلاً من document، مما يمنع حدوث تعارضات عند وجود إصدارات متعددة من React في نفس الوقت.📖 ملخص
- يستخدم React SyntheticEvent، الذي يضمن التوافق بين المتصفحات والتطهير التلقائي
- الأحداث الشائعة: onClick، onChange، onSubmit، onKeyDown، onFocus/onBlur
- استخدم الدوال السهمية لتمرير معلمات إضافية
onClick={() => handler(id)} event.preventDefault()منع السلوك الافتراضي،event.stopPropagation()منع انتقال التأثير- لا تكتب
onClick={handler(id)}(فسيتم تنفيذه على الفور)؛ استخدمonClick={() => handler(id)}بدلاً من ذلك.
📝 تمارين
- تمرين أساسي (مستوى الصعوبة ⭐): أنشئ مكونًا باسم
ButtonCounterيعمل على زيادة العدد المعروض بمقدار 1 في كل مرة يتم فيها النقر على الزر. استخدم الحدثonClick. - تمرين متقدم (مستوى الصعوبة ⭐⭐): أنشئ مكونًا
SearchInputيُنفِّذ ميزة «البحث بعد إزالة الارتداد»: حيث يتم تشغيل عملية البحث تلقائيًّا بعد مرور 500 مللي ثانية من توقف المستخدم عن الكتابة. استخدمonChangeوuseEffect. - التحدي (الصعوبة: ⭐⭐⭐): أنشئ مكونًا
DragAndDropListيُنفِّذ عملية الفرز بالسحب والإفلات. استخدم أحداثonDragStartوonDragOverوonDrop. يمكن سحب عناصر القائمة إلى مواقع جديدة.