• בלוג
  • שימוש ב props.children מתוך פקד ריאקט גנרי

שימוש ב props.children מתוך פקד ריאקט גנרי

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

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

פוסט זה זמין גם בשפה האנגלית בקישור:
https://ynonperek.wordpress.com/2015/09/26/building-a-generic-content-slider-in-react-js/

1. לאן רוצים להגיע

המטרה היא להגיע לפקד ContentSlider כך שנוכל לכתוב את הקוד הבא בתוכנית ריאקט:

var App = React.createClass({
  render: function() {
    return <ContentSlider>
          <img src="https://pbs.twimg.com/media/CBgCOOQW8AA3OCq.png" />
          <img src="https://pbs.twimg.com/media/CINXyYQWwAA_hlT.jpg" />
          <img src="https://updatesfromthefield.files.wordpress.com/2010/12/lolcat2.jpg" />
          <p>Just remember that death is not the end</p>
      </ContentSlider>
  }
});

והתוצאה תיראה כך (לחצו על הכפתורים מתחת לתמונה כדי לראות את התמונות מתחלפות):

2. מבנה הפקד

פקד ContentSlider מורכב משני חלקים: בחלק העליון יש לנו את התוכן ובחלק התחתון את הכפתורים לעבור בין פריטי התוכן השונים. התוכן בחלק העליון מורכב בתורו מ div חיצוני בגובה ורוחב חסומים עם מאפיין overflow:hidden, בתוכו div פנימי עם רוחב שמספיק להכניס את כל פריטי התוכן אחד ליד השני ובתוכו כל פריטי התוכן. 
על הפריטים עצמם אנו נרצה להוסיף את הקלאס slider-item, ואילו שני המיכלים יקבלו את הקלאסים slider-inner ו slider-outer בהתאמה. כך נראה ה CSS עבור הפקד:

.slider-outer {
  display:block;
  position:relative;
  overflow:hidden;
  width:200px;
  height:200px;  
}

.slider-inner {
  display:block;
  position:absolute;
  transition: all 0.5s;
}

.slider-item {
  display:inline-block;
  width:200px;
  height:200px;  
  vertical-align:top;
}

כדי להשאיר את הדוגמא פשוטה בחרתי ברוחב וגובה קבועים של 200 פיקסלים. בקוד אמיתי תרצו לאפשר לקבל את המידע מבחוץ או לחשב דינמית לפי פריטי התוכן הפנימיים. 

3. עדכון הילדים בקלאס החדש

בתוך קוד הפקד אנו יכולים לגשת לפריטי התוכן באמצעות המאפיין this.props.children. האתגר הראשון שלנו הוא לעדכן את פריטי התוכן וכאן יש לזכור שבריאקט אנו לא נוהגים לעדכן properties מתוך פקד. גם המאפיין children הוא לא חריג ולכן במקום לעדכן את הערך הקיים מומלץ לבנות מערך חדש של אלמנטים אותם נוכל לשנות. הפקודה React.cloneElement משמשת לשכפול אלמנטי ילדים לצורך שימוש בהם בפקד מיכל. קוד השכפול נראה בערך כך:

var newChildren = React.Children.map(this.props.children, function(child) {
  return React.cloneElement(child, { foo: true })
});

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

var newChildren = React.Children.map(this.props.children, function(child) {
  return React.cloneElement(child, { className: "slider-item" })
});

וקוד הפקד המלא נראה כך:

4. סיכום וקריאת המשך

התיחסות לפקדי ילדים בריאקט לא שונה משמעותית מהתיחסות ל properties אחרים שמועברים לפקד, אך מאפשרת קשר בין פקדים שעוזר לכתוב קוד קריא יותר. במקום להעביר לפקד ImageSlider מערך של תמונות לבנות אנו יכולים להעביר את המערך מבחוץ וכך לקבל קוד גנרי יותר, שיכול לקבל תמונה, טקסט או כל אלמנט אחר. מאחר ושכפול הילדים מבוצע ב render המאפיינים עצמם של הילדים נקבעים בכל הפעלת render, מה שנותן לכם שליטה מלאה כיצד יראו הילדים כנגזרת של מצב הפקד בכל רגע נתון.

הבלוג הרשמי של ריאקט שם הם מספרים על React.cloneElement ולמה הוסיפו אותה (זוהי פקודה חדשה שהתווספה בגירסא 0.13):
https://facebook.github.io/react/blog/2015/03/03/react-v0.13-rc2.html

הפונקציה cloneElement בתיעוד:
https://facebook.github.io/react/docs/top-level-api.html