الاستجابة للأحداث
يتيح لك React إضافةمعالجات الأحداثإلى JSX الخاص بك. معالجات الأحداث هي دوال خاصة بك سيتم تشغيلها استجابةً للتفاعلات مثل النقر، والتأشير، وتركيز مدخلات النموذج، وما إلى ذلك.
سوف تتعلم
- طرق مختلفة لكتابة معالج حدث
- كيفية تمرير منطق معالجة الأحداث من مكون أب
- كيفية انتشار الأحداث وكيفية إيقافها
إضافة معالجات الأحداث
لإضافة معالج حدث، ستقوم أولاً بتعريف دالة ثمتمريرها كخاصيةإلى وسم JSX المناسب. على سبيل المثال، إليك زر لا يفعل شيئًا بعد:
يمكنك جعله يعرض رسالة عندما ينقر المستخدم باتباع هذه الخطوات الثلاث:
- قم بتعريف دالة تسمى
handleClickداخلمكونButtonالخاص بك. - نفذ المنطق داخل تلك الدالة (استخدم
alertلعرض الرسالة). - أضف
onClick={handleClick}إلى وسم<button>في JSX.
لقد قمت بتعريف دالةhandleClick ثم مررتها كخاصيةإلى<button>.handleClick هو معالج حدث.دوال معالج الأحداث:
- عادةً ما تُعرَّفداخلمكوناتك.
- أسماؤها تبدأ بـ
handle، متبوعةً باسم الحدث.
وفقًا للاصطلاح الشائع، من المعتاد تسمية معالجات الأحداث بـhandleمتبوعةً باسم الحدث. ستشاهد غالبًاonClick={handleClick}، وonMouseEnter={handleMouseEnter}، وهكذا.
بدلاً من ذلك، يمكنك تعريف معالج حدث مباشرةً في JSX:
أو، بشكل أكثر إيجازًا، باستخدام دالة السهم:
كل هذه الأنماط متكافئة. معالجات الأحداث المضمنة ملائمة للدوال القصيرة.
مشكلة شائعة
يجب تمرير الدوال إلى معالجي الأحداث، وليس استدعاؤها. على سبيل المثال:
| تمرير دالة (صحيح) | استدعاء دالة (غير صحيح) |
|---|---|
<button onClick={handleClick}> | <button onClick={handleClick()}> |
الفرق دقيق. في المثال الأول، يتم تمرير دالةhandleClickكمعالج حدثonClick. هذا يخبر React أن تتذكرها وتستدعي دالتك فقط عندما ينقر المستخدم على الزر.
في المثال الثاني،()في نهايةhandleClick()تشغل الدالةفورًاأثناء عمليةالتصيير، دون أي نقرات. هذا لأن JavaScript داخلJSX { و }تُنفذ على الفور.
عند كتابة الكود مباشرةً (inline)، تظهر نفس المشكلة بطريقة مختلفة:
| تمرير دالة (صحيح) | استدعاء دالة (غير صحيح) |
|---|---|
<button onClick={() => alert('...')}> | <button onClick={alert('...')}> |
تمرير كود مباشر مثل هذا لن يشغله عند النقر—سيشغله في كل مرة يتم فيها تصيير المكون:
إذا أردت تعريف معالج الحدث مباشرةً، فلفه داخل دالة مجهولة كما يلي:
بدلاً من تنفيذ الكود داخله مع كل عملية تصيير، هذا ينشئ دالة ليتم استدعاؤها لاحقًا.
في كلتا الحالتين، ما تريد تمريره هو دالة:
<button onClick={handleClick}>يمرر دالةhandleClick.<button onClick={() => alert('...')}>يمرر دالة() => alert('...').
قراءة الخصائص في معالجات الأحداث
نظرًا لأن معالجات الأحداث تُعرَّف داخل المكون، فإن لديها وصولًا إلى خصائص المكون. إليك زر، عند النقر عليه، يعرض تنبيهًا يحتوي على خاصيةmessageالخاصة به:
هذا يتيح لهذين الزرين عرض رسائل مختلفة. جرب تغيير الرسائل المُمررة إليهما.
تمرير معالجات الأحداث كخاصية (Props)
غالبًا ما ترغب في أن يحدد المكون الأب معالج الأحداث للمكون الفرعي. فكر في الأزرار: اعتمادًا على المكان الذي تستخدم فيه مكونButton، قد ترغب في تنفيذ وظيفة مختلفة—ربما واحدة تشغّل فيلمًا وأخرى ترفع صورة.
للقيام بذلك، مرر خاصية (prop) يستقبلها المكون من أبيه كمعالج الأحداث كما يلي:
هنا، يقوم مكونToolbar بعرض PlayButton و UploadButton:
PlayButtonيمررhandlePlayClickكخاصيةonClickإلى مكونButtonالموجود بداخله.UploadButtonيمرر() => alert('Uploading!')كخاصيةonClickإلى مكونButtonالموجود بداخله.
أخيرًا، يستقبل مكونكButtonخاصية تسمىonClick. إنه يمرر تلك الخاصية مباشرة إلى مكون المتصفح المدمج<button>باستخدامonClick={onClick}. هذا يخبر React باستدعاء الدالة المُمررة عند النقر.
إذا كنت تستخدمنظام تصميم (design system)، فمن الشائع أن تحتوي المكونات مثل الأزرار على التنسيقات ولكن لا تحدد السلوك. بدلاً من ذلك، ستقوم مكونات مثلPlayButton و UploadButtonبتمرير معالجات الأحداث إلى الأسفل.
تسمية خصائص معالجات الأحداث
المكونات المدمجة مثل<button> و <div>تدعم فقطأسماء أحداث المتصفحمثلonClick. ومع ذلك، عندما تبني مكوناتك الخاصة، يمكنك تسمية خصائص معالجات الأحداث الخاصة بها بأي طريقة تريدها.
وفقًا للاصطلاح، يجب أن تبدأ خصائص معالجات الأحداث بـon، متبوعة بحرف كبير.
على سبيل المثال، كان يمكن تسمية الخاصيةButtonالخاصة بالمكونonClick باسم onSmash:
في هذا المثال، يظهر<button onClick={onSmash}>أن زر المتصفح<button>(بحروف صغيرة) لا يزال يحتاج إلى خاصية تسمىonClick، لكن اسم الخاصية التي يستقبلها مكونك المخصصButtonمتروك لك!
عندما يدعم مكونك تفاعلات متعددة، قد تسمي خصائص معالجات الأحداث وفقًا لمفاهيم خاصة بالتطبيق. على سبيل المثال، يستقبل مكونToolbar
لاحظ كيف أن مكونAppلا يحتاج إلى معرفةما الذيToolbarسيفعله بـonPlayMovieأوonUploadImage. هذا تفصيل تنفيذي خاص بـToolbar. هنا، يقومToolbarبتمريرهما كمعالجاتonClickإلى أزرارهButton، ولكنه يمكن لاحقًا أيضًا تشغيلهما باستخدام اختصار لوحة المفاتيح. تسمية الخصائص بناءً على تفاعلات خاصة بالتطبيق مثلonPlayMovieتمنحك المرونة لتغيير طريقة استخدامها لاحقًا.
ملاحظة
تأكد من استخدام وسوم HTML المناسبة لمعالجات الأحداث لديك. على سبيل المثال، للتعامل مع النقرات، استخدم<button onClick={handleClick}>بدلاً من<div onClick={handleClick}>. استخدام<button>حقيقي للمتصفح يمكّن السلوكيات المدمجة في المتصفح مثل التنقل باستخدام لوحة المفاتيح. إذا كنت لا تحب التنسيق الافتراضي للمتصفح للزر وتريد جعله يبدو أكثر مثل رابط أو عنصر واجهة مستخدم مختلف، يمكنك تحقيق ذلك باستخدام CSS.تعرف على المزيد حول كتابة ترميز يمكن الوصول إليه.
انتشار الحدث
ستلتقط معالجات الأحداث أيضًا الأحداث من أي مكونات فرعية قد تكون لدى مكونك. نقول إن الحدث "يتصاعد" أو "ينتشر" لأعلى الشجرة: يبدأ من مكان حدوث الحدث، ثم يصعد لأعلى الشجرة.
تحتوي هذه<div>على زرين. كل من<div>وكل زر لديه معالجاتonClickالخاصة به. أي المعالجات تعتقد أنها ستنشط عند النقر على زر؟
إذا نقرت على أي من الزرين، فإنonClickالخاص به سيعمل أولاً، يليه<div>الأبonClick. لذا ستظهر رسالتان. إذا نقرت على شريط الأدوات نفسه، فإن<div>الأب فقطonClickسيعمل.
مشكلة محتملة
جميع الأحداث تنتشر في React باستثناءonScroll، والذي يعمل فقط على وسم JSX الذي ترفقه به.
إيقاف الانتشار
تستقبل معالجات الأحداثكائن حدثكوسيط وحيد لها. حسب الاصطلاح، يُسمى عادةًe، وهو اختصار لـ "event". يمكنك استخدام هذا الكائن لقراءة معلومات عن الحدث.
يسمح لك كائن الحدث هذا أيضًا بإيقاف الانتشار. إذا أردت منع وصول حدث إلى المكونات الأصل، فأنت بحاجة إلى استدعاءe.stopPropagation()كما يفعل مكونButton هذا:
عندما تنقر على زر:
- يستدعي React معالج
onClickالذي تم تمريره إلى<button>. - يقوم ذلك المعالج، المحدد في
Button، بما يلي:- يستدعي
e.stopPropagation()، مما يمنع الحدث من الانتشار أكثر. - يستدعي دالة
onClick، وهي خاصية (prop) تم تمريرها من مكونToolbar.
- يستدعي
- تقوم تلك الدالة، المحددة في مكون
Toolbar، بعرض تنبيه الزر الخاص به. - بما أن الانتشار تم إيقافه، فإن معالج
<div>الأبonClickلايعمل.
نتيجة لـe.stopPropagation()، يؤدي النقر على الأزرار الآن إلى عرض تنبيه واحد فقط (من<button>) بدلاً من التنبيهين (من<button>ومن شريط الأدوات الأب<div>). النقر على زر ليس هو نفسه النقر على شريط الأدوات المحيط، لذا فإن إيقاف الانتشار منطقي لهذه الواجهة.
تمرير المعالجات كبديل للانتشار
لاحظ كيف يشغل معالج النقر هذا سطراً من الشفرةثميستدعي خاصيةonClickالتي مررها الأب:
يمكنك إضافة المزيد من الشفرة إلى هذا المعالج قبل استدعاء معالج حدثonClickالأب أيضاً. يوفر هذا النمطبديلاًللانتشار. فهو يسمح للمكون الفرعي بالتعامل مع الحدث، بينما يسمح أيضاً للمكون الأب بتحديد بعض السلوكيات الإضافية. على عكس الانتشار، فهو ليس تلقائياً. لكن فائدة هذا النمط هي أنه يمكنك تتبع سلسلة الشفرة بأكملها التي يتم تنفيذها نتيجة لبعض الأحداث بوضوح.
إذا كنت تعتمد على الانتشار وكان من الصعب تتبع المعالجات التي تعمل ولماذا، فجرب هذه الطريقة بدلاً من ذلك.
منع السلوك الافتراضي
بعض أحداث المتصفح لها سلوك افتراضي مرتبط بها. على سبيل المثال، حدث إرسال<form>، والذي يحدث عند النقر على زر بداخله، سيعيد تحميل الصفحة بأكملها افتراضياً:
يمكنك استدعاءe.preventDefault()على كائن الحدث لمنع حدوث ذلك:
لا تخلط بينe.stopPropagation() و e.preventDefault(). كلاهما مفيدان، لكنهما غير مرتبطين:
- e.stopPropagation()توقف معالجات الأحداث المرفقة بالوسوم الأعلى عن التنفيذ.
- e.preventDefault()تمنع السلوك الافتراضي للمتصفح للأحداث القليلة التي تمتلكه.
هل يمكن أن يكون لمعالجات الأحداث تأثيرات جانبية؟
بالتأكيد! معالجات الأحداث هي أفضل مكان للتأثيرات الجانبية.
على عكس دوال التصيير، لا تحتاج معالجات الأحداث إلى أن تكوننقية، لذا فهي مكان رائعلتغييرشيء ما—على سبيل المثال، تغيير قيمة حقل إدخال استجابةً للكتابة، أو تغيير قائمة استجابةً لضغط زر. ومع ذلك، لتغيير بعض المعلومات، تحتاج أولاً إلى طريقة لتخزينها. في React، يتم ذلك باستخدامالحالة، ذاكرة المكون.ستتعلم كل شيء عنها في الصفحة التالية.
ملخص
- يمكنك التعامل مع الأحداث عن طريق تمرير دالة كخاصية prop لعنصر مثل
<button>. - يجب تمرير معالجات الأحداث،لا استدعاؤها!
onClick={handleClick}، وليسonClick={handleClick()}. - يمكنك تعريف دالة معالجة الأحداث بشكل منفصل أو مضمن.
- يتم تعريف معالجات الأحداث داخل مكون، لذا يمكنها الوصول إلى الخصائص props.
- يمكنك الإعلان عن معالج حدث في المكون الأب وتمريره كخاصية prop إلى المكون الابن.
- يمكنك تعريف خصائص معالجات الأحداث الخاصة بك بأسماء خاصة بالتطبيق.
- تنتشر الأحداث للأعلى. استدعِ
e.stopPropagation()على الوسيط الأول لمنع ذلك. - قد يكون للأحداث سلوك متصفح افتراضي غير مرغوب فيه. استدعِ
e.preventDefault()لمنع ذلك. - استدعاء خاصية معالج حدث بشكل صريح من معالج الابن هو بديل جيد للانتشار.
جرب بعض التحديات
Challenge 1 of 2:إصلاح معالج حدث #
من المفترض أن يؤدي النقر على هذا الزر إلى تبديل خلفية الصفحة بين الأبيض والأسود. ومع ذلك، لا يحدث شيء عند النقر عليه. أصلح المشكلة. (لا تقلق بشأن المنطق داخل handleClick—فهذا الجزء بخير.)
