צרות של ריאקט ו ES6 Classes

פוסט זה כולל טיפ קצר בנושא פיתוח Front End. אם אתם רוצים ללמוד יותר לעומק על פיתוח Front End מהבסיס ועד הנושאים המתקדמים תשמחו לשמוע שבניתי קורס וידאו מקיף בנושא זה הכולל מעל 50 שיעורי וידאו והמון תרגול מעשי.
למידע נוסף והצטרפות לקורס בקרו בדף קורס Front End באתר.
 

נראה שכל הילדים המגניבים עברו לכתוב ריאקט עם ES6 Classes וכמוהם גם אני ניסיתי, עד שנתקלתי בבעיה המרגיזה הבאה שגרמה לי לתכנן מסלול מחדש.

1. איך עובדת ירושה ב ES6

ב ES6 כשאתם בונים מחלקה שיורשת ממחלקה אחרת ודורסים פונקציה של המחלקה האחרת, עליכם לקרוא באופן יזום ל super כדי להפעיל את הפונקציה מהמחלקה האחרת. זה אגב לא ייחודי ב JavaScript וקיים ברוב השפות שאני מכיר שיש בהן מנגנון ירושה.

קוד ES6 הבא לדוגמא יזרוק שגיאה כי ב Vehicle לא מוגדרת הפונקציה drive:

class Vehicle {}

class Car extends Vehicle {
  drive() {
    super.drive();
    console.log('Vroom Vroom');
  }
}

const c = new Car();
c.drive();

אותה השגיאה תזרק גם מ TypeScript ומשפות רבות נוספות. אי אפשר לקרוא ל super מפונקציה שלא דרסתם. 

2. ועכשיו נחזור לריאקט

הבעיה בריאקט היא פונקציות Licecycle של פקד, פונקציות כגון componentDidMount, setState, componentDidUpdate וכן הלאה. כשתרצו להגדיר פונקציית omponentDidUpdate משותפת למספר פקדים אולי תטעו לחשוב שכדאי לבנות מחלקת פקד-אב וכל הפקדים ירשו ממנו:

class Common extends React.Component {
  componentDidUpdate(nextProps, nextState) {
    console.log('new props for component: ' + JSON.stringify(nextProps));
  }
}

class TextBox extends Common {
  componentDidUpdate(nextProps, nextState) {
    super.componentDidUpdate(nextProps, nextState);

    // handle textbox specific update logic
  }
}

עכשיו יש לכם מוקש בקוד: ברגע שתמחקו מ Common את המימוש ל componentDidUpdate כל שאר הפקדים שירשו ממנו ישברו. 

אפשר לטעון כמובן שהבעיה הזו לא ייחודית לריאקט או ל ES6, אבל לדעתי טיעון כזה יהיה בעייתי: הבעיה האמיתית היא שהפונקציה componentDidUpdate משמשת כפונקציה מיוחדת (hook) ופונקציות כאלו היינו מצפים שיוגדרו עם מימוש ריק במחלקת האב React.Component, כך שכל אחד יוכל להגדיר או לא להגדיר קוד טיפול לפי הצורך. במקרה של ריאקט מצד אחד אתם חייבים להשתמש בשם הספציפי componentDidUpdate, מה שמייצר היררכיות ירושה מאוד שבירות.

הפתרון? להגדיר את כל מימושי ברירת המחדל של פונקציות מחזור החיים של ריאקט בפקד-אב שיורש מ React.Component ושכל הפקדים שלכם ירשו ממנו ולא מ React.Component. בקוד הפקדים תמיד תוכלו לקרוא ל super ולדעת שהקוד שלכם לא יישבר.