React: معالجة الأحداث

آخر تحديث: 2026-08-26

معالجة الأحداث هي النهايات العصبية لتطبيق React — فعندما ينقر المستخدمون على الأزرار، أو يدخلون نصًا، أو يرسلون نماذج، يتم الرد على هذه التفاعلات من خلال الأحداث. ويُعد نظام الأحداث في React أكثر ذكاءً وتوحيدًا من أحداث DOM الأصلية.


1. ما ستتعلمه



2. قصة عن التفاعل مع النماذج

(1) نقاط الضعف: 3 عقبات في عملية إرسال النماذج

يعمل بوب على إنشاء نموذج لتسجيل المستخدمين وكتابة معالجات الأحداث بلغة جافا سكريبت الأصلية:

JAVASCRIPT
// 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......'
})

مشكلة بوب:

(2) معالجة الأحداث في React

JSX
function RegisterForm() {
  const [name, setName] = React.useState('')
  const [isSubmitting, setIsSubmitting] = React.useState(false)

  // Submit for Processing
  function handleSubmit(event) {
    event.preventDefault()
    setIsSubmitting(true)
    
    fetch('/api/register', {
      method: 'POST',
      body: JSON.stringify({ name })
    }).finally(() => setIsSubmitting(false))
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={name}
        onChange={e => setName(e.target.value)}
        placeholder="Please enter your name"
      />
      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? 'Submitting......' : 'Register'}
      </button>
    </form>
  )
}
▶ جرّب الكود

المزايا: تم تقليص حجم الكود من 30 سطراً إلى 15 سطراً، دون الحاجة إلى التعديل على DOM، ودون مواجهة أي مشكلات تتعلق بإلغاء ربط الأحداث، ودون أي مشكلات تتعلق بتوافق المتصفحات.



3. الأحداث المركبة في React

أحداث React ليست أحداث DOM أصلية، بل هي SyntheticEvents — حيث يستمع React إليها على المستوى الأعلى ويحاكي نظام أحداث متوافق مع جميع المتصفحات.

ميزة أحداث DOM الأصلية أحداث React المركبة
طريقة الربط addEventListener / onclick الكتابة مباشرةً بلغة JSX
التوافق مع المتصفحات يلزم التعامل اليدوي مع الاختلافات التوحيد التلقائي
إدارة الذاكرة يجب إزالة المستمعين يدويًّا التنظيف التلقائي
كائن الحدث الحدث الأصلي الحدث الاصطناعي
منع تكوّن الفقاعات event.stopPropagation() متطابق (موحد)
الحظر الافتراضي event.preventDefault() كما هو (موحد)
100%
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


4. مرجع سريع للأحداث الشائعة

اسم الحدث شروط التشغيل السيناريوهات الشائعة نوع كائن الحدث
onClick النقر على عنصر زر، رابط، بطاقة MouseEvent
onChange التغييرات في محتوى حقول الإدخال حقول النماذج، القوائم المنسدلة ChangeEvent
onSubmit إرسال النموذج تسجيل الدخول/التسجيل/البحث FormEvent
onFocus يتم تحديد العنصر يتم تمييز حقل الإدخال FocusEvent
onBlur فقد العنصر التركيز التحقق من صحة المدخلات FocusEvent
onKeyDown اضغط على أي مفتاح مفتاح الاختصار، اضغط على Enter للبحث KeyboardEvent
onKeyUp الأخبار والبيانات الصحفية البحث في الوقت الفعلي KeyboardEvent
onMouseEnter التمرير بالماوس تأثير التمرير MouseEvent
onMouseLeave عند إبعاد الماوس تأثير التمرير MouseEvent
onScroll التمرير التمرير اللانهائي UIEvent

▶ مثال: نظرة عامة شاملة على الأحداث الشائعة

JSX 📖 للعرض فقط
// ============================================
// Example:Complete Event Handling for a Login Form
// ============================================

function LoginForm() {
  const [email, setEmail] = React.useState('')
  const [password, setPassword] = React.useState('')
  const [errors, setErrors] = React.useState({})
  const [focusedField, setFocusedField] = React.useState('')

  function handleSubmit(event) {
    event.preventDefault()
    
    // Form Validation
    const newErrors = {}
    if (!email.includes('@')) newErrors.email = 'The email address format is incorrect.'
    if (password.length < 6) newErrors.password = 'Password must be at least 6 chars'
    
    if (Object.keys(newErrors).length > 0) {
      setErrors(newErrors)
      return
    }
    
    // Submit Login
    console.log('Log In:', { email, password })
  }

  function handleKeyDown(event) {
    // Press Escape key to clear focus
    if (event.key === 'Escape') {
      event.target.blur()
    }
  }

  return (
    <form onSubmit={handleSubmit} style={{ maxWidth: '400px', margin: '0 auto' }}>
      <h2>Log In</h2>

      {/* Enter your email address */}
      <div style={{ marginBottom: '16px' }}>
        <label>Email:</label>
        <input
          type="email"
          value={email}
          onChange={e => setEmail(e.target.value)}
          onFocus={() => setFocusedField('email')}
          onBlur={() => { setFocusedField(''); setErrors({...errors, email: undefined}) }}
          onKeyDown={handleKeyDown}
          style={{
            width: '100%',
            padding: '8px',
            borderColor: errors.email ? '#ff4d4f' : focusedField === 'email' ? '#1890ff' : '#d9d9d9'
          }}
        />
        {errors.email && <p style={{ color: '#ff4d4f', fontSize: '12px' }}>{errors.email}</p>}
      </div>

      {/* Password Entry */}
      <div style={{ marginBottom: '16px' }}>
        <label>Password:</label>
        <input
          type="password"
          value={password}
          onChange={e => setPassword(e.target.value)}
          onFocus={() => setFocusedField('password')}
          onBlur={() => setFocusedField('')}
          onKeyDown={handleKeyDown}
          style={{
            width: '100%',
            padding: '8px',
            borderColor: errors.password ? '#ff4d4f' : focusedField === 'password' ? '#1890ff' : '#d9d9d9'
          }}
        />
        {errors.password && <p style={{ color: '#ff4d4f', fontSize: '12px' }}>{errors.password}</p>}
      </div>

      {/* Submit Button */}
      <button
        type="submit"
        onClick={() => console.log('Clicked the "Log In" button')}
        onMouseEnter={() => console.log('Button on Mouse Hover')}
        onMouseLeave={() => console.log('Mouse leaves button')}
        style={{
          width: '100%',
          padding: '10px',
          backgroundColor: '#1890ff',
          color: 'white',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer'
        }}
      >
        Log In
      </button>
    </form>
  )
}
81 سطر من الكود المنطقي (تجاوز الحد 40, للعرض فقط)

5. تمرير معلمات الأحداث

(1) تمرير المعلمات مباشرةً

قم بتغليفها في دالة سهمية وقم بتمرير المعلمات الإضافية مباشرةً:

JSX
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) استرداد كلاً من كائن الحدث والمعلمات المخصصة

JSX
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()

أكثر حالات الاستخدام شيوعًا هي منع تحديث الصفحة عند إرسال نموذج:

JSX
function SearchForm() {
  const [query, setQuery] = React.useState('')

  function handleSubmit(event) {
    event.preventDefault()  // Prevent the page from refreshing
    // Execute Custom Search Logic
    console.log('Search:', query)
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={query}
        onChange={e => setQuery(e.target.value)}
        placeholder="Search..."
      />
      <button type="submit">Search</button>
    </form>
  )
}

// Other scenarios where the default behavior needs to be overridden:
// - Link Redirection:<a href="#" onClick={e => e.preventDefault()}>
// - Context Menu:onContextMenu={e => e.preventDefault()}
// - Drag-and-Drop File Upload:onDragOver={e => e.preventDefault()}
▶ جرّب الكود

(2) منع تكوّن الفقاعات: stopPropagation()

JSX
function Modal() {
  return (
    // Click the mask layer to close the pop-up window
    <div
      style={overlayStyle}
      onClick={() => console.log('Click the mask layer → Close Pop-up')}
    >
      {/* Clicking on the pop-up content does not display a speech bubble */}
      <div
        style={modalStyle}
        onClick={(event) => {
          event.stopPropagation()  // Prevent Bubbles from Rising to the Mask Layer
          console.log('Click on the pop-up window content')
        }}
      >
        <h2>Pop-up Title</h2>
        <p>Pop-up Content</p>
        <button onClick={() => console.log('Close')}>Close</button>
      </div>
    </div>
  )
}

// Click "Modal Content" area → only triggers modal onClick
// Click "Overlay" (outside modal) → trigger mask layer onClick
▶ جرّب الكود

7. مثال كامل: قائمة المهام (معالجة الأحداث الشاملة)

JSX
// ============================================
// Example:Todo List(Comprehensive Incident Handling)
// Features:Add a Task、Marked as complete、Delete Task、Double-click to edit
// ============================================

function TodoApp() {
  const [todos, setTodos] = React.useState([
    { id: 1, text: 'Study React Event', done: false },
    { id: 2, text: 'Complete the homework', done: false }
  ])
  const [input, setInput] = React.useState('')

  // 1. Add a Task(onSubmit + Enter key)
  function handleSubmit(event) {
    event.preventDefault()
    if (!input.trim()) return
    
    setTodos([...todos, {
      id: Date.now(),
      text: input.trim(),
      done: false
    }])
    setInput('')
  }

  // 2. Quick Add with the Enter Key(onKeyDown)
  function handleKeyDown(event) {
    if (event.key === 'Enter' && input.trim()) {
      handleSubmit(event)
    }
  }

  // 3. Switch to "Completed" status(onChange)
  function handleToggle(id) {
    setTodos(todos.map(t =>
      t.id === id ? { ...t, done: !t.done } : t
    ))
  }

  // 4. Delete Task(onClick + Parameter Passing)
  function handleDelete(id, event) {
    event.stopPropagation()  // Prevent triggering li the incident
    setTodos(todos.filter(t => t.id !== id))
  }

  // 5. Double-click to edit(onDoubleClick)
  function handleEdit(todo) {
    const newText = prompt('Edit Task:', todo.text)
    if (newText && newText.trim()) {
      setTodos(todos.map(t =>
        t.id === todo.id ? { ...t, text: newText.trim() } : t
      ))
    }
  }

  return (
    <div style={{ maxWidth: '500px', margin: '0 auto' }}>
      <h2>📋 Todo List</h2>

      {/* Input Form */}
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={e => setInput(e.target.value)}
          onKeyDown={handleKeyDown}
          placeholder="Input Task,Press Enter to add..."
          style={{
            width: '70%', padding: '8px',
            border: '1px solid #d9d9d9', borderRadius: '4px'
          }}
        />
        <button type="submit" style={{
          padding: '8px 16px', marginLeft: '8px',
          backgroundColor: '#1890ff', color: 'white',
          border: 'none', borderRadius: '4px', cursor: 'pointer'
        }}>
          Add
        </button>
      </form>

      {/* Statistics */}
      <p style={{ color: '#666', fontSize: '14px' }}>
        Total {todos.length} items, Completed {todos.filter(t => t.done).length} items
      </p>

      {/* Task List */}
      <ul style={{ listStyle: 'none', padding: 0 }}>
        {todos.map(todo => (
          <li
            key={todo.id}
            onDoubleClick={() => handleEdit(todo)}
            style={{
              display: 'flex', alignItems: 'center',
              padding: '10px', margin: '4px 0',
              backgroundColor: todo.done ? '#f6ffed' : '#fff',
              border: '1px solid #f0f0f0',
              borderRadius: '4px',
              textDecoration: todo.done ? 'line-through' : 'none',
              color: todo.done ? '#999' : '#333',
              cursor: 'pointer'
            }}
          >
            {/* Checkbox */}
            <input
              type="checkbox"
              checked={todo.done}
              onChange={() => handleToggle(todo.id)}
              style={{ marginRight: '10px' }}
            />

            {/* Mission Text */}
            <span style={{ flex: 1 }}>{todo.text}</span>

            {/* Delete Button */}
            <button
              onClick={(e) => handleDelete(todo.id, e)}
              style={{
                padding: '2px 8px',
                backgroundColor: 'transparent',
                color: '#ff4d4f',
                border: 'none',
                cursor: 'pointer',
                fontSize: '16px'
              }}
            >
              ✕
            </button>
          </li>
        ))}
      </ul>
    </div>
  )
}

مسار التفاعل:

  1. اكتب اسم المهمة في مربع النص، ثم اضغط على مفتاح Enter، أو انقر على زر «إضافة» → تُضاف المهمة إلى القائمة
  2. حدد مربع الاختيار → ضع علامة على المهمة على أنها مكتملة (يظهر النص مشطوبًا وباللون الرمادي)
  3. انقر على زر ✕ → احذف المهمة (stopPropagation لمنع النقر المزدوج من تشغيل وظيفة التحرير)
  4. انقر نقرًا مزدوجًا على أي مهمة → يظهر مربع حوار للتحرير

▶ المثال 2: اختصارات لوحة المفاتيح وإدارة التركيز

JSX
// ============================================
// Example:Shortcut Keys Panel——Integrated Use of Keyboard Events and Focus Management
// Features:Usage onKeyDown Implement Keyboard Shortcuts,Usage onFocus/onBlur Management Focus
// ============================================

function ShortcutPanel() {
  const [output, setOutput] = React.useState('')
  const [activeKeys, setActiveKeys] = React.useState(new Set())
  const inputRef = React.useRef(null)

  // Keyboard Event Handling
  function handleKeyDown(event) {
    const { key, ctrlKey, shiftKey, altKey } = event

    // Ctrl+S:Save
    if (ctrlKey && key === 's') {
      event.preventDefault()
      setOutput('💾 Saved(Ctrl+S)')
    }
    // Ctrl+Z:Revoke
    else if (ctrlKey && key === 'z') {
      event.preventDefault()
      setOutput('↩️ Undo(Ctrl+Z)')
    }
    // Escape:Clear Output
    else if (key === 'Escape') {
      setOutput('')
      event.target.blur()
    }
    // Enter:Confirm
    else if (key === 'Enter') {
      setOutput(`✅ Confirm:${event.target.value || '(Empty input)'}`)
    }

    // Display the currently pressed key
    setActiveKeys(prev => new Set([...prev, key]))
  }

  function handleKeyUp(event) {
    setActiveKeys(prev => {
      const next = new Set(prev)
      next.delete(event.key)
      return next
    })
  }

  // Autofocus
  React.useEffect(() => {
    inputRef.current.focus()
  }, [])

  return (
    <div style={{ maxWidth: '500px', margin: '0 auto' }}>
      <h2>⌨️ Shortcut Keys Panel</h2>

      <input
        ref={inputRef}
        onKeyDown={handleKeyDown}
        onKeyUp={handleKeyUp}
        onFocus={() => setOutput('The input field is currently focused')}
        onBlur={() => setOutput('The input field has lost focus')}
        placeholder="Type here,Try the shortcut keys..."
        style={{
          width: '100%',
          padding: '10px',
          fontSize: '16px',
          border: '2px solid #1890ff',
          borderRadius: '6px',
          outline: 'none'
        }}
      />

      {/* Keyboard Shortcut Tips */}
      <div style={{ marginTop: '12px', display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
        {[
          { key: 'Ctrl+S', desc: 'Save' },
          { key: 'Ctrl+Z', desc: 'Revoke' },
          { key: 'Enter', desc: 'Confirm' },
          { key: 'Escape', desc: 'Clear/blur' }
        ].map(shortcut => (
          <span key={shortcut.key} style={{
            padding: '4px 10px',
            backgroundColor: '#f5f5f5',
            border: '1px solid #d9d9d9',
            borderRadius: '4px',
            fontSize: '12px',
            fontFamily: 'monospace'
          }}>
            {shortcut.key} <span style={{ color: '#999' }}>{shortcut.desc}</span>
          </span>
        ))}
      </div>

      {/* Currently Pressed Key */}
      {activeKeys.size > 0 && (
        <p style={{ marginTop: '8px', fontSize: '13px', color: '#666' }}>
          Currently Pressed Key:{[...activeKeys].join(' + ')}
        </p>
      )}

      {/* Operation Output */}
      {output && (
        <div style={{
          marginTop: '12px',
          padding: '10px',
          backgroundColor: '#f6ffed',
          border: '1px solid #b7eb8f',
          borderRadius: '4px',
          color: '#52c41a',
          fontWeight: 'bold'
        }}>
          {output}
        </div>
      )}
    </div>
  )
}

▶ المثال 3: التعامل مع أحداث الفرز بالسحب والإفلات

JSX
function DragSortList() {
  const [items, setItems] = useState(['Apple', 'Banana', 'Cherry', 'Date'])
  const [dragIdx, setDragIdx] = useState(null)

  function handleDragStart(idx) { setDragIdx(idx) }

  function handleDragOver(e, idx) {
    e.preventDefault()
    if (dragIdx === null || dragIdx === idx) return
    setItems(prev => {
      const updated = [...prev]
      const [moved] = updated.splice(dragIdx, 1)
      updated.splice(idx, 0, moved)
      return updated
    })
    setDragIdx(idx)
  }

  function handleDragEnd() { setDragIdx(null) }

  return (
    <div style={{ maxWidth: 300, margin: '0 auto' }}>
      <h3>Drag to Reorder</h3>
      {items.map((item, idx) => (
        <div key={item} draggable
          onDragStart={() => handleDragStart(idx)}
          onDragOver={e => handleDragOver(e, idx)}
          onDragEnd={handleDragEnd}
          style={{
            padding: '8px 12px', marginBottom: 4, borderRadius: 4, cursor: 'grab',
            background: dragIdx === idx ? '#e6f7ff' : '#f5f5f5',
            border: dragIdx === idx ? '2px solid #1890ff' : '2px solid transparent',
          }}>
          {item}
        </div>
      ))}
    </div>
  )
}
▶ جرّب الكود

▶ المثال 4: ربط مخصص لتغليف مستمعي الأحداث

JSX
function useEventListener(event, handler, element = window) {
  useEffect(() => {
    element.addEventListener(event, handler)
    return () => element.removeEventListener(event, handler)
  }, [event, handler, element])
}

function MouseTracker() {
  const [pos, setPos] = useState({ x: 0, y: 0 })
  const handler = useCallback(e => setPos({ x: e.clientX, y: e.clientY }), [])
  useEventListener('mousemove', handler)

  return (
    <div style={{ padding: 20 }}>
      <p>Mouse: ({pos.x}, {pos.y})</p>
      <div style={{
        width: 200, height: 200, border: '1px solid #ddd', position: 'relative', borderRadius: 4,
      }}>
        <div style={{
          width: 10, height: 10, borderRadius: '50%', background: '#1890ff',
          position: 'absolute', left: Math.min(pos.x - 100, 190), top: Math.min(pos.y - 100, 190),
          transition: 'left 0.1s, top 0.1s',
        }} />
      </div>
    </div>
  )
}
▶ جرّب الكود

▶ المثال 5: إرسال النموذج ودمج الأحداث

JSX
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>
  )
}
▶ جرّب الكود

❓ أسئلة شائعة

س لماذا نستخدم دالة السهم () => handleClick(id) بدلاً من handleClick(id) فقط؟
ج إذا كتبت onClick={handleClick(id)} مباشرةً، فسوف يقوم React بتنفيذ handleClick(id) فورًا أثناء عملية العرض، بدلاً من الانتظار حتى يتم النقر عليها. وذلك لأنها استدعاء دالة (مع أقواس)، وليست إشارة إلى دالة (بدون أقواس). الطريقة الصحيحة هي onClick={() => handleClick(id)} (دالة السهم مع التنفيذ المؤجل) أو onClick={handleClick} (الإشارة المباشرة إلى اسم الدالة عند عدم تمرير أي معلمات).
س هل يمكن ربط عدة أحداث متطابقة بعنصر واحد؟
ج لا يمكنك ربط حدثين onClick مباشرةً. الحلول: ① استدعاء عدة دوال onClick={() => { fn1(); fn2() }} داخل نفس معالج الأحداث؛ ② أو تغليف العنصر بعدة HOCs. عادةً، لا يحتاج العنصر سوى إلى معالج أحداث واحد، يمكنك من خلاله استدعاء عدة أجزاء من المنطق.
س ما الفرق بين الأحداث الاصطناعية في React والأحداث الأصلية؟
ج SyntheticEvent في React هو غلاف متعدد المتصفحات للأحداث الأصلية، يوفر واجهة برمجة تطبيقات موحدة (مثل e.preventDefault() وe.stopPropagation()) ويعمل بشكل متسق عبر جميع المتصفحات. تعمل الأحداث الاصطناعية في إطار آلية تفويض الأحداث — حيث يتم ربط جميع الأحداث بالعقدة الجذرية بدلاً من عناصر DOM الفردية. في React 17 والإصدارات الأحدث، يتم تفويض الأحداث إلى العقدة الجذرية بدلاً من document، مما يمنع حدوث تعارضات عند وجود إصدارات متعددة من React في نفس الوقت.

📖 ملخص


📝 تمارين

  1. تمرين أساسي (مستوى الصعوبة ⭐): أنشئ مكونًا باسم ButtonCounter يعمل على زيادة العدد المعروض بمقدار 1 في كل مرة يتم فيها النقر على الزر. استخدم الحدث onClick.
  2. تمرين متقدم (مستوى الصعوبة ⭐⭐): أنشئ مكونًا SearchInput يُنفِّذ ميزة «البحث بعد إزالة الارتداد»: حيث يتم تشغيل عملية البحث تلقائيًّا بعد مرور 500 مللي ثانية من توقف المستخدم عن الكتابة. استخدم onChange وuseEffect.
  3. التحدي (الصعوبة: ⭐⭐⭐): أنشئ مكونًا DragAndDropList يُنفِّذ عملية الفرز بالسحب والإفلات. استخدم أحداث onDragStart وonDragOver وonDrop. يمكن سحب عناصر القائمة إلى مواقع جديدة.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%