ניסוי בטכנולוגיות צד-לקוח (React.js)

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

react
הפוסט נכתב על ידי ליאור בר און, איתמר שגב וניר בנימין.
Angular.js, ספריית ה-MVC מבית גוגל לצד-הלקוח, הופכת לבחירה יותר ויותר מקובלת בקרב מפתחים. כיום, היא אחד הנושאים המדוברים ביותר בטכנולוגיות צד-לקוח. בצד ההגמוניה ההולכת ונבנית ע”י אנגולר בצד-הלקוח, נשמעים בד בדד, גם קולות הטוענים שאנגולר מורכבת מדי – שאפשר לעשות את הדברים בצורה פשוטה יותר. פשטות היא ערך משמעותי בעולם הקוד הפתוח ובצד הלקוח בפרט. אחד הקולות הללו מגיע מצד פייסבוק ואינסטגרם. הפתרון שלהם: ספרייה ששוחררה לפני כשנה בשם react.js.

React.js (להלן “ראקט”), לא תתחרה באנגולר ראש-בראש בעתיד הנראה לעין: אנגולר היא מקיפה הרבה יותר (הן פונקציונלית והן תהליכית), ומתאימה הרבה יותר ל-mainstream. ראקט פותרת רק חלק קטן ממה שאנגולר פותרת – ועושה זו בצורה לא שגרתית, מה שעלול להרחיק ממנה מפתחים רבים מהמיינסטרים. היא אנדרדוג. כמה מהרעיונות שלה מקוממים במבט ראשון. אולי גם במבט שני.

יש כבר כמה דוגמאות לשימושים ב-React.js במוצרים מרכזיים [א]: פייסבוק (חלקים), אינסטגרם (עם ה-router של backbone) ו-Khan Academy (עם Backbone). ניתן למצוא עליה דיונים ב-StackOverflow ואפילו יש 4 גרסאות שונות שלה לשימוש ב-jsFiddle.אפילו אם ראקט לא “תתפוס” – הרעיונות שלה מעניינים מספיק בכדי שיהיה שווה להכיר אותם ולחשוב עליהם. האם היא באה להעיר את תשומת לבנו לאבדן הדרך שהולך ומתרחש? או אולי סתם להציג עוד נקודת מבט אפשרית?יצאנו לבדוק במה מדובר…פוסט זה מסכם ניסיון של 3 ימים בכתיבה בראקט, שהתרחשה במסגרת “האקתון” במעבדות SAP

מה ראקט מציעה?

הדבר הראשון הניכר משימוש בראקט הוא מ-Client Side Rendering מהיר ביותר. ראקט יכולה לשמש לכתיבת אפליקציות שמרגישות מאוד “חלקות” ולא נתקעות. היא מתאימה לאפליקציות בעלות רינדור אינטנסיבי.

עד כמה שזה מרשים – זה עדיין לא פיצ’ר שמצדיק שימוש בספרייה עבור רוב המשתמשים. היכולות הללו בעיקר קוסמות למי שנמצא ב-extreme optimization של אפליקציות ווב (כמו חברי “מועדון ה sub-second”) ומחפש דרך לאופטימיזציה גבוהה מאוד, מבלי לחרב את הקוד.

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

ראקט מציעה לנו לבטל את עדכון ה-DOM: כאשר יש צורך בעדכון כלשהו, פשוט נהרוס את ה-DOM של האפליקציה כולו – ונבנה את כולו מחדש בעזרת לוגיקת “הבנייה הראשונית”.

פשוט, לא?מבחינת ביצועים, רעיון זה הוא חסר היגיון: כתיבה ל-DOM היא יקרה מאוד. ראקט מנהלת DOM וירטואלי אותו ניתן לעדכן במהירות רבה. המהירות מאפשרת סגנון כתיבה פשוט יותר – כתיבת ה-DOM ללא התחשבות במצבו הקודם.

אפליקציית ראקט טיפוסית מתחילה בקריאת:

 React.RenderComponent(<root component name>);
היוצרת את רכיב האב וקוראת ל ()render שלו. הוא מצידו יקרא ייצור מופעים של רכיבים בנים (משולבים ב-HTML markup) – ויקרא ל-render שלהם וכך חוזר חלילה לעומק עץ של רכיבים ו-markup.כאשר יש שינוי ב-state של אחד הרכיבים – פונקציית ה ()render של אותו רכיב תקרא ותרגום לעדכון של תת העץ שלו.
הרכיבים בראקט מגדירים את המראה שלהם בעזרת Markup ורכיבים בנים, כאשר הם לא כותבים ישירות ל-DOM של הדפדפן לא רק ל-React.DOM – ה-DOM הוירטואלי שראקט מנהלת.כפי שציינו, כתיבה ל-DOM היא פעולה יקרה. יתרה מכך: הדפדפן מחזיק Buffer קטן של כתיבות ל-DOM אותן הוא מנסה לאגד לאצווה, אולם כל קריאה מה-DOM עשויה להכריח אותו לכתוב ל-DOM בנקודת זמן לא רצויה (מדוע? הסבר בפוסט זה, “ההשפעה של פעולות DOM מתוך קוד ג’אווהסקריפט”).מכיוון שראקט מנהלת עותק שלה של ה-DOM, היא יכולה לקרוא ולכתוב ל-DOM הווירטואלי שלה מבלי לעדכן את ה-DOM של הדפדפן. כמו כן היא יכולה לסדר פעולות ל-DOM בצורה אופטימלית מבחינת ביצועים (סדרות של קריאות וסדרות של כתיבות).כאשר היא רוצה לעדכן את ה-DOM של הדפדפן, היא עושה diff יעיל (להלן הסבר האלגוריתם) של ה-DOM הווירטואלי וה-DOM האמיתי ומעדכנת ב-DOM האמיתי רק אלמנטים שבאמת השתנו. כמובן, שכדי שזה יעבוד, אין לערבב על אותו אזור ב-DOM את ראקט עם ספריה אחרת שכותבת ל-DOM ישירות.
ראקט מחלקת את הטקסט לרכיבים אטומיים קטנים, כך שיהיה אפשר לעדכן רק את ה nodes של הערכים (בירוק), מבלי לעדכן את הערכים של ה Labels (בצהוב). שימו לב למספור שראקט מייצרת על ה-DOM (תכונת data-reactid) – בעזרתו היא מבצעת השאוות יעילות של ה-DOM.
הרעיון של Virtual DOM אינו חדש, אגב: Backbase הציגה מין Virtual DOM משלה לפני שנים (היא כנראה לא היחידה), וטכניקה דומה נמצאת בשימוש במנועים גרפיים של משחקי מחשב.
הניתוק מה-DOM מאפשר לראקט גם לרוץ בצד השרת (עבור מכשירים חלשים / sub-second load time) – ממש כמו rendr עבור Backbone.js.
השוואה לא מדוייקת בין האתר Hacker News (שורה עליונה) ו clone שלו שכתבנו בראקט (שורה תחתונה). אדום – טעינה ראשונית. בכחול – פעולת דפדפוף בין הכתבות (האתר שלנו היה הרבה-הרבה יותר מהיר). פרופיל ה timeline שקבלנו מקוד הראקט מאוד לא אופייני לאתר / אפליקציה שלא עברה עדיין שום אופטימיזציית ביצועים.

 דוגמת קוד

אין כמו לראות קצת קוד.

הנה אפליקציה פשוטה למדי עם 2 כפתורים (++X ו ++Y) המעלים את הערכים של ה-counters המתאימים במרכז המסך.

התוצאה הסופית של האפליקציה

קוד ב-react ניתן לכתוב באחד מ-2 סגננונות: JSX ו”ג’אווהסקריפט נקי”. JSX הוא הרחבה לג’אווה סקריפט עם XML (מבוסס E4X?), המאפשרת לכתוב snippets של XML בתוך הג’אווה סקריפט ע”פ חוקים מסויימים.

JSX אמור להיות פשוט יותר ונקי יותר לכתיבה – ועל כן מועדף ע”י החלק הגדול של מפתחי ראקט. ה-JSX מקומפל לג’אווה סקריפט רגיל לפני שהוא מורץ על הדפדפן. ניתן לקמפל אותו בתוך הדפדפן ע”י הוספת קובץ ג’אווה סקריפט בשם JSXTransformer (לפיתוח מהיר יותר) או בצד השרת ע”י רכיב מתאים של Node (לביצועים טובים יותר).

אנו עבדנו ב-IDE בשם WebStorm (מומלץ) שקיבל יפה מאוד את הרחבות ה-XML בתוך קובצי ה-javaScrit, והמשיך לתפקד היטב עם קוד הג’אווה סקריפט (hinting, ניווט, וכו’).

עוד וריאציה נפוצה יחסית לשימוש בראקט היא כתיבה ב-CoffeeScript על מנת לכתוב קוד מינימליסטי של ראקט ללא JSX.

בדוגמה זו נראה כתיבה בצורת JSX ולאחר מכן, את הגרסה המקומפלת שלה ל”ג’אווה סקריפט נקי”.
  1. כאשר משתמשים ב-JSX Transformer בכדי לקמפל JSX “תוך כדי שימוש” (“on the fly”) – חייבים לכלות הערה זו בתחילת הקובץ.
  2. אנו מגדירים רכיב (component) פשוט של ראקט, בשם Simple.
  3. את הרצת התוכנה בראקט מבצעים בעזרת פקודת renderCompoent על הרכיב הראשי. שימו לב לתגים ה Simple – שאיננה סטנדרטית ב HTML, אלא מבטאת את הרכיב שלנו. אנו שולחים לרכיב ה-Simple שלנו Property (בלתי ניתן לשינוי immutable) – בשם message ואומרים לראקט להוסיף את הרכיב בתוך document.body (קרי InnerHTML).
  4. אחד השלבים הראשונים במחזור החיים של רכיב react הוא קריאה למתודה ()getInitialState המאתחלת את ה-state של הרכיב. בשלב זה, ניתן להבין שזהו stateful component.
  5. שלב מעט מאוחר יותר במחזור החיים של הרכיב, הוא הקריאה למתודה ()render המייצרת את ה-markup של הרכיב – ומחזירה אותו לרכיב האב (במקרה זה – זהו רכיב האב).
  6. יצירת ה-markup נעשית על ידי כתיבה inline של markup ב JSX. עטפנו הכל בסוגריים כדי שנוכל למקם את ה div הראשון בשורה חדשה (אסור בג’אווהסקריפט לסיים שורה ב return).
  7. סוגריים מסולסלות הוא ה-escaping לשילוב ביטויי ג’אווה סקריפט בתוך ה-XML (חייב לחזור ערך). במקרה זה אנו קוראים לאובייקט ה-properties של הרכיב (שהוא immutable  – בלתי ניתן לשינוי). את הערך של התכונה message קבענו בשלב 3.
  8. באופן דומה אנו רושמים מטפלים לאירועים (incX, incY).
  9. כאשר האירועים נקראים (בעקבות לחיצה של העכבר על אחד הכפתורים), מספיק שנשנה את ה-state של הרכיב – כדי ש-react ידאג לקרוא ל-render, ובצורה יעילה (למשל: לא יותר מפעם אחת ב Animation Frame של הדפדפן).
  10. לתחביר ה-XML יש כמה תכונות מיוחדות: למשל הטיפול ב-inline style attribute.
ניתן למצוא online JSX compiler בקישור הבא
כפי שאפשר להבחין, ה-markup שאנו כותבים ב-JSX הוא איננו HTML. זהו XML שרק דומה ל-HTML. הסיבה לשימוש ב-XML הוא הצורך ב-markup קל לפענוח – HTML הוא מאוד סלחן ובעייתי לפענוח.
הדרך הכי בולטת לשים לב להבדל בין ה-JSX XML ו-HTML היא לקחת דוגמת HTML מהאינטרנט (שעובדת!) ולהדביק אותה לתוך האפליקציה. כמה הבדלים מרכזיים הם:
  1. אלמנטים חייבים להסגר. לא עוד <br> אלא רק </ br >.
  2. מכיוון שה-markup מקומפל לג’אווהסקריפט, לא ניתן להשתמש במלים שמורות של שפת ג’אווהסקריפט. למשל, במקום תכונת class משתמשים ב-className.
  3. inline style attribute לא נכתב כמו ב HTML, אלא כאובייקט – כמו בדוגמת הקוד למעלה. אפשר גם לכתוב אותה inline בעזרת סוגריים מסולסלים כפולים {{…}}=style.

בסה”כ, בניגוד לציפיותנו, התרגלנו לכתיבת ה-XML דיי מהר – והיא לא היוותה מטרד מיוחד. מעניין לציין ש-react עושה escaping ל-markup בכדי להגן בפני חולשות XSS.

הנה הקוד לאחר שקומפל ל-JavaScript בעזרת ה-JSX Transformer:

הודאה קטנה: זה לא בדיוק הקוד. הקוד שנוצר הוא מעט “עמוס” בגלל השימוש ב-“React.DOM” בכל מקום – ולכן עשינו לביטוי זה extract למשתנה שפחות תופס את העין: קו תחתון (בירוק).

הכנסנו את הביטוי במקום שורת רווח כדי לא “לקלקל” את מספרי השורות. ה-JSX Transformer דואג לשמר את מספרי השורות בין ה-source JSX לתוצר ה-javaScript שנוצר.

סיכום ורשמים אישיים

ראקט דורשת קצת זמן הסתגלות: אנו ניסינו אותה במהלך סוג של “האקתון” שערך שלושה ימי כתיבה, במסגרת מקום העבודה. רק ביום השלישי התחלנו להתרגל לסגנון הכתיבה בראקט (וגם אז – לא כולנו). התיעוד שלה – לא טוב. את רוב התשובות מצאנו ב-stackoverflow וכמעט לא בתיעוד הרשמי. נציין שכל נושא שלא עניין אותנו, דווקא היה מתועד בצורה מופתית (“חוק מרפי של התיעוד”).
נתקענו כמה פעמים על בעיות, לזמן לא קצר – אך בסוף הצלחנו לפתור את הבעיות ולהבין את מקורן. למשל גילינו, בדרך הקשה, שקביעת ערך לאובייקט ה-state (כלומר (…)setState) לא מתרחשת מיידית, אלא היא מנוהלת בתור ומבוצעת רק לפני ציור ה Activation Frame (כלומר האירוע בו הדפדפן מעדכן את תצוגת המסך, שאמור להתרחש 60 פעמים בשנייה). קביעת ערך בפונציה א’ לא מבטיח שזה הערך שיקרא מאובייקט ה state בפונקציה ב’ שמתרחשת מיד לאחר מכן. עדיף להעביר את הערך כפרטמר לפונקציה ולא להסתמך על ה state שיהיה מעודכן.האפליקציה שכתבנו התרנדרה בצורה מהירה מאוד, גם ללא מאמץ שהושקע מצדנו. החלוקה לרכיבים הסתדרה בצורה טובה, אם כי זו אפליקציה קטנה. סה”כ הקוד בדיעבד נראה סביר ומסודר. עוד נושא שלא בדקנו ונשאר כשאלה פתוחה היא הקלות לכתוב בדיקות יחידה: המצאותו של ה-Virtual DOM עשויה בהחלט לעזור – אך לא ניסינו זאת עדיין.היינו מנסים את react.js בעתיד באפליקציות לא-גדולות ועתירות רינדור (הייתה לנו אחת כזו לפני מספר חודשים). מכיוון שרקאט היא לא כ”כ דומה ל-frameworks אחרים, כדאי כנראה להשתמש בה רק בצוות שירגיש נוח איתה – לרוב מפתחי client-side hardcore הרגילים לכתוב קרוב ל-DOM. שאר המפתחים – יוכלו להמתין שראקט תתבגר עוד קצת ותגיע לגרסה…נאמר, 0.5.
*  *  *

קישורים

פוסט על בדיקות יחידה ב react.js

[א] בהשוואה לאנגולר, ניתן להזכיר שגוגל לא משתמשת באנגולר במוצרים המרכזיים שלה.

כתב אורח

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

הגב

3 תגובות על "ניסוי בטכנולוגיות צד-לקוח (React.js)"

avatar
Photo and Image Files
 
 
 
Audio and Video Files
 
 
 
Other File Types
 
 
 

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

סידור לפי:   חדש | ישן | הכי מדורגים
גדעון
Guest

אחלה סקירה!

איליה
Guest

קבוצה של REACT ISRAEL. תרשמו…http://www.meetup.com/ReactJS-IL/

איליה
Guest

רוצים לדעת עוד על REACT או FLUX ARCHITECTURE כנסו לדף הפייסבוק של הקבוצה

https://www.facebook.com/pages/Reactjs-IL/1519114138377541

wpDiscuz

תגיות לכתבה: