בגרסא 16.6 של ריאקט קיבלנו תוספות מעולות שנותנות לנו כמפתחים את היכולת לעשות code splitting לקוד שלנו ממש בקלות. בפוסט זה נתמקד בתכונות החדשות, lazy ו- Suspense
ואיך ניתן להשתמש בהם בריאקט.
מה זה Code splitting
אפליקציית ריאקט גדולה תכלול בדרך כלל המון קומפוננטות, ספריות צד שלישי ופונקציות עזר (utility functions). אם לא נעשה מאמץ לנסות לטעון חלקים שונים באפליקציה רק בעת הצורך ישלח bundle אחד גדול למשתמשים בעת טעינת העמוד הראשון. דבר אשר יכול להשפיע על ביצועי האפליקציה באופן משמעותי.
כדי להימנע מ-bundle אחד גדול אנחנו נדאג לפצל את ה-bundle שלנו באמצעות code splitting.
code splitting היא יכולת הנתמכת על ידי bundlers כמו Webpack ו- Browserify שיכולים בעצם ליצור מספר bundles שניתן לטעון באופן דינמי בזמן ריצה(לפי דרישה), משמע נטען באנדל אחד הרבה יותר קטן בטעינה ראשונית ובאנדלים נוספים יטענו לפי צורך שאנחנו נגדיר. חשוב להדגיש שריאקט לא מבצעת את ה- code splitting אלא נותנת לנו API סופר פשוט כדי לממש אותו בקוד שלנו.
מתי נשתמש ב- Code splitting
בכל פעם שאנו מכניסים תלות חדשה (ספריה,קומפוננטה) לפרויקט שלנו, האחריות שלנו היא להעריך את ״העלות״ שלה לפרוייקט ולבדוק כיצד היא משפיעה על הבאנדל הראשי.
כעת נשאל את עצמינו מה היוזר צריך בזמן נתון? האם התלות החדשה עומדת לשמש אותנו לעיתים רחוקות(ראוט שאחוז קטן מאוד מגיעים אליו, כפתור שבעת לחיצה צריך ספריה ספציפית וכו..) והאם נוכל לייבא אותה לפי דרישה מבלי לפגוע בחווית המשתמש. אם התשובה היא כן, React.Lazy ו- Suspense יעזרו לנו במשימה זו.
אינדיקציה נוספת בשבילנו היא להציץ בקונסול לאחר build. אם הבאנדל הראשי גדול מידי תהיה אזהרה שתפנה אותנו ל- code splitting.
![](https://www.react-israel.co.il/wp-content/uploads/2019/08/bundle.png)
יש לציין ש- React.Lazy ו- Suspense עדיין לא זמינות ב- server side rendering. הצוות של ריאקט ממליץ על שימוש ב –Loadable components למי שעדיין ירצה לעשות Code splitting
React.lazy
lazy נותנת לנו לייבא קומפוננטות שנטענות באמצעות ייבוא דינמי( dynamic import) אך ירונדרו כמו קומפוננטות רגילות. שימוש ב- lazy יגרום אוטומטית לטעינה של הבאנדל המכיל את הקומפוננטה בעת זמן הרנדור שלה ולא בבאנדל הראשי.
lazy מקבלת פונקציה כארגיומנט שמחזיר promise על ידי קריאה ל-import כדי לטעון את הקומפוננטה. ה- promise שמוחזר מכיל מודול עם ייצוא ברירת מחדל (default export) המכיל את הקומפוננטה.
נשמע קצת מסובך? המון מושגים? אבל באמת שזה ממש פשוט. בואו נראה איך משתמשים ב- lazy
קודם נראה דוגמא לאיך הקוד שלנו נראה לפני
וכעת נראה איך הקוד שלנו יראה לאחר שימוש ב lazy
זה כל ״הקסם״. ה-jsx שלנו נראה בדיוק אותו דבר השוני היחיד הוא בדרך שבא אנחנו עושים import.
כדי להמחיש את הדוגמא נטען ספריה גדולה ובואו נראה מה קורה בלשונית network.
![](https://www.react-israel.co.il/wp-content/uploads/2019/08/before.png)
שימו לב לגודל של o.chunk . כעת נייבא את הספריה באמצעות lazy. גודל הבאנדל שלנו ירד דרמטית(מזכיר שבכוונה ייבאנו ספריה עם משקל גבוה) ורק לאחר לחיצה על כפתור(שבעצם יבצע פעולה מסויימת עם אותה ספריה) נרצה לטעון אותה ולקבל את היכולות שלה
![](https://www.react-israel.co.il/wp-content/uploads/2019/08/Screen-Shot-2019-08-07-at-15.42.07.png)
אנחנו יכולים לראות ש- 0.chunk ירד משמעותית בגודל שלו. באו נראה מה יקרה לאחר לחיצה על כפתור שיביא את הקומפוננטה lazy שלנו.
![](https://www.react-israel.co.il/wp-content/uploads/2019/08/Screen-Shot-2019-08-07-at-15.17.58.png)
לאחר לחיצה על הכפתור הבאנו דינמית את הקומפוננטה הרצויה.ראו chunk.4 chunck.3
וכך לא העמסנו על הבאנדל הראשי ויצרנו קומפוננטות דינמיות שנטענות לפי צורך
React.Suspense
קומפוננטה שנוצרה באמצעות lazy נטענת רק כאשר יש לרנדר אותה, לכן עולה הצורך להציג איזשהו loader בזמן טעינת הקומפוננטה. בדיוק לשם כך נוצר Suspense
ל-Suspense
יש פרופ בשם Fallback שיודע לקבל קומפוננטה אותה הוא יציג בעת ההמתנה לטעינה של הקומפוננטה שאמורה להתרנדר. אנחנו יכולים למקם את Suspense
בכל מקום מעל לקומפוננטה שנוצרה עם lazy (או ללא, או גם וגם)
בואו נראה דוגמא
שימוש ב- Suspense עבור מספר קומפוננטות
בעזרת Suspense
נוכל ״להשעות״ מספר קומפוננטות מלהטען אפילו אם כולן מיובאות בעזרת lazy
בואו נראה דוגמא שתמחיש לנו את המצב
הדוגמא הנל שימושית ביותר לעיכוב ההצגה של מספר קומפוננטות תוך הצגת לואדר אחד. רק לאחר שכל הקומפוננטות יסיימו להטען היוזר יראה את כולן מוצגות בו זמנית.
שימוש ב-lazy על הראוטר
עם lazy ו- Suspense
אנחנו יכולים לבצע Code splitting על הראוטים שלנו. נמיר את הקומפוננטות שהרואטים משתמשים בהם ל-lazy ונעטוף את כולם ב-Suspense
(לא חובה שכל הרואטים ימומשו באמצעות lazy-תלוי בבהחלטות שניקח)
לסיכום
עם התוספות החדשות בגרסא 16.6, lazy ו- Suspense הצוות של ריאקט עשו לנו חיים קלים ונוחים בכל מה שקשור ל code splitting של קומפוננטות ריאקט.
בכל פעם שאנו מכניסים תלות חדשה לפרויקט שלנו, באחריותינו להעריך את העלות שלה ולבדוק כיצד היא משפיעה על הבאנדל הראשי.
כמו כן עלינו לשאול את עצמינו האם נשתמש בתלות זו לעיתים רחוקות והאם נוכל לטעון אותה לפי דרישה(dynamically ) מבלי לפגוע בחווית המשתמש.
אם אנחנו לא בטוחים היכן כדאי לנו ליישם code splitting הייתי מתחיל ב:
- Router- ראוטרים הם הדרך הפשוטה ביותר לזהות מקומות שבהן ניתן לפצל את האפליקציה שלנו.
- זיהוי קומפונטטות גדולות באפליקציה שמתרנדרות רק באינטרקציה מסוימת של היוזר(לחיצה על כפתור למשל)
- כל דבר שהוא מ״חוץ״ למסך ולא קריטי למשתמש.
חשוב לזכור שאנחנו לא רוצים לפגוע בחוויות המשתמש ואין צורך לבצע lazy לכל קומפוננטה.
אם אהבתם את המאמר אשמח אם תשתפו/תמליצו לאחרים, אם יש לכם שאלות או הערות תוכלו להשאיר אותם בתגובות מתחת.