React מטפלת באירועים עם props שנקראים על שם האירוע ב-camelCase, כמו onClick, onChange ו-onSubmit. מעבירים פונקציה, ו-React קוראת לה עם אובייקט אירוע כשהמשתמש לוחץ, מקליד או שולח.
כל לחיצה מריצה את handleClick, שמעדכנת את הספירה ורושמת לקונסול מתחת לתצוגה המקדימה. נסו onDoubleClick במקום onClick: עכשיו רק לחיצה כפולה נספרת.
מעבירים את הפונקציה, לא קוראים לה
ה-prop מקבל פונקציה, ו-React קוראת לה אחר כך. טעות נפוצה מאוד היא להוסיף סוגריים, מה שקורא לפונקציה מיד, בזמן הרינדור, ומעביר ל-React את ערך ההחזרה שלה במקום.
הקונסול מציג "Hi, during render" לפני שנגעתם במשהו: React הריצה את sayHi בזמן שרינדרה את הכפתור הראשון, ומכיוון ש-sayHi מחזירה undefined, לכפתור הזה אין handler בכלל. לחיצה על Wrong לא עושה כלום. לחיצה על Right רושמת "Hi, Ada", כי פונקציית החץ רצה רק בלחיצה.
פונקציית החץ היא גם הדרך להעביר ארגומנטים. onClick={() => removeItem(item.id)} יוצר פונקציה קטנה לכל פריט, והפונקציה הזו קוראת לשלכם עם ה-ID הנכון. אם handler לא מקבל ארגומנטים, העבירו אותו לפי שם: onClick={handleClick}.
עם setter של state הטעות גרועה יותר: onClick={setCount(count + 1)} קובע state בזמן הרינדור, מה שמרנדר שוב, מה שקובע state שוב, ו-React עוצרת עם "Too many re-renders".
אובייקט האירוע
React מעבירה לכל handler ארגומנט אחד, אובייקט האירוע. יש לו אותם מאפיינים כמו לאירוע של הדפדפן: e.target הוא האלמנט שעליו האירוע קרה, e.key הוא המקש שנלחץ, e.preventDefault() מבטל את פעולת ברירת המחדל של הדפדפן. React עוטפת את האירוע הנייטיב במה שהיא קוראת לו synthetic event, כך שהוא מתנהג אותו דבר בכל דפדפן; המקורי נמצא ב-e.nativeEvent אם תצטרכו אותו.
השניים שמשתמשים בהם הכי הרבה הם e.target.value ב-onChange ו-e.key ב-onKeyDown.
הקלידו hooks ולחצו Enter: התגית נוספת והשדה מתנקה. הקונסול רושם כל מקש, כולל Shift, Backspace ו-Enter, לפי השמות ב-e.key. לחצו Escape באמצע מילה כדי לזרוק אותה.
ה-onChange של React מופעל בכל הקשה. ב-HTML רגיל האירוע change על שדה טקסט מופעל רק כשהוא מאבד פוקוס, אז זה הבדל מכוון: הוא מאפשר לשדה ול-state להישאר מתואמים אות אחר אות. checkboxes נותנים לכם e.target.checked במקום value. הדף על טפסים מכסה כל סוג קלט.
טפסים ו-preventDefault
כששולחים טופס, פעולת ברירת המחדל של הדפדפן היא לשלוח אותו ולטעון דף חדש. באפליקציית React כמעט תמיד רוצים לטפל בנתונים בעצמכם, ולכן ה-handler של השליחה מתחיל ב-e.preventDefault().
שימו onSubmit על ה-<form>, לא onClick על הכפתור: כך גם לחיצה על Enter בשדה שולחת, והבדיקות של הדפדפן עצמו (כאן required ו-type="email") רצות קודם. מחקו את השורה e.preventDefault() ושלחו שוב: דף אמיתי היה עובר עכשיו לדף חדש ומאבד את הודעת התודה. התצוגה המקדימה חוסמת את זה ומציגה במקום מה הטופס היה שולח, email= בלי ערך, כי setEmail('') כבר ניקה את השדה כשהטופס נקרא.
React 19 גם מאפשרת להעביר פונקציה ל-<form action={fn}>, שמקבלת את נתוני הטופס ומאפסת בשבילכם שדות לא מבוקרים. הדף על טפסים מראה את שני הסגנונות.
bubbling ו-stopPropagation
רוב האירועים עושים bubbling: אחרי שהם רצים על האלמנט שלחצתם עליו, הם רצים על ההורה שלו, ואז על ההורה של ההורה, עד למעלה. handlers של React עוקבים אחרי אותו סדר. לכן לחיצה על כפתור בתוך כרטיס לחיץ נחשבת גם ללחיצה על הכרטיס.
לחצו על Bubbles up והקונסול רושם את הכפתור, אחר כך את הפאנל הפנימי, ואז את הכרטיס החיצוני. לחצו על Stops here ורק הכפתור נרשם: e.stopPropagation() עוצר את הטיפוס. לחיצה על הטקסט של הפאנל הפנימי עצמו רושמת את הפאנל ואת הכרטיס.
השתמשו ב-stopPropagation במשורה. מקרה לגיטימי נפוץ הוא כפתור מחיקה בתוך שורה לחיצה ברשימה, שבו לחיצה על מחיקה לא אמורה גם לפתוח את השורה. אם הורה צריך לדעת אם הלחיצה הגיעה מילד, בדקו את e.target במקום לעצור את האירוע. כדי להריץ handler בדרך מטה, לפני שהילדים רואים את האירוע, React מציעה גרסאות capture כמו onClickCapture.
preventDefault ו-stopPropagation הם כלים שונים. הראשון מבטל את מה שהדפדפן היה עושה (לעבור לקישור, לשלוח טופס, לסמן checkbox). השני מונע מ-handlers אחרים לשמוע על האירוע. קריאה לאחד לא עושה את השני.
אירועים נפוצים אחרים
אותו דפוס מכסה כל אירוע ש-React תומכת בו. כמה שתשתמשו בהם לעיתים קרובות:
onFocusו-onBlurמופעלים כששדה מקבל ומאבד פוקוס, שימושי להצגת ולידציה אחרי שהמשתמש עוזב שדה.onMouseEnterו-onMouseLeaveמופעלים כשהסמן נכנס לאלמנט ויוצא ממנו. בניגוד לרוב האירועים הם לא עושים bubbling, כך שמעבר של הסמן מהורה לתוך הילד שלו לא מפעיל שוב את ה-onMouseEnterשל ההורה.onPointerDown,onPointerMoveו-onPointerUpעובדים עם עכבר, מגע ועט באותה מידה, ולכן הם הבחירה הטובה יותר לגרירה.onScrollמופעל כשאלמנט נגלל. ב-React הוא לא עושה bubbling.
כל handler מקבל אובייקט אירוע עם המאפיינים שהגיוניים עבורו: e.clientX לאירועי pointer, e.key לאירועי מקלדת, e.target לכולם.
העברת handlers כ-props
קומפוננטות יכולות לקבל handlers מההורה שלהן כמו כל prop אחר. קראו להם onSomething לפי מה שקרה, ולפונקציה שמטפלת בזה handleSomething. זה משקף את האירועים המובנים ומבהיר אילו props הם callbacks.
Stepper לא מחזיקה את המספר; היא מדווחת על לחיצות וההורה מחליט מה הן אומרות. שנו את handleDecrement כך שייעצר ב-1 במקום 0, וה-stepper יעקוב בלי שיערכו אותו. החזקת state בהורה והעברת handlers מטה היא הדפוס שמתואר ב-הרמת state למעלה.
props של handlers מותאמים הם רק שמות. onIncrement על קומפוננטה משלכם לא עושה כלום עד שהקומפוננטה מעבירה אותו ל-onClick של אלמנט אמיתי, ואפשר לתת לו כל ארגומנט שרוצים, למשל onSelect(item.id).
שאלות נפוצות
איך מעבירים פרמטר ל-handler של onClick?
עטפו את הקריאה בפונקציית חץ: onClick={() => deleteItem(item.id)}. פונקציית החץ היא מה ש-React קוראת לו בלחיצה, והיא קוראת לפונקציה שלכם עם הארגומנט.
למה ה-onClick שלי רץ כשהדף נטען?
קראתם לפונקציה במקום להעביר אותה. onClick={handleClick()} מריץ את handleClick בזמן הרינדור ומעביר את ערך ההחזרה שלה. כתבו onClick={handleClick} או onClick={() => handleClick(id)}.
מה ההבדל בין onChange ב-React לבין HTML?
ב-HTML האירוע change על שדה טקסט מופעל כשהשדה מאבד פוקוס. ה-onChange של React מופעל בכל הקשה, כמו האירוע הנייטיב input, כך שה-state יכול לעקוב אחרי הטקסט תוך כדי הקלדה.
איך מונעים מטופס לרענן את הדף ב-React?
קראו ל-e.preventDefault() בתחילת ה-handler של onSubmit. שימו את ה-handler על ה-<form>, לא על כפתור השליחה, כך שגם לחיצה על Enter בשדה שולחת את הטופס.
מה זה synthetic event ב-React?
זה אובייקט האירוע ש-React מעבירה ל-handlers שלכם. הוא עוטף את האירוע הנייטיב של הדפדפן עם אותם מאפיינים ומתודות (target, key, preventDefault(), stopPropagation()) ומתנהג אותו דבר בכל הדפדפנים. המקורי זמין בתור e.nativeEvent.