לדלג לתוכן

רשימת בדיקה לביצועים בריאקט - Performance Checklist

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

תפסו רינדורים מיותרים לפני שהם נהיים בעיה

הדבר הראשון שכדאי לבדוק הוא האם קומפוננטות מתרנדרות כשהן לא באמת צריכות. קומפוננטת ילד שמקבלת props שלא השתנו בפועל, אבל בכל זאת מתרנדרת מחדש בכל פעם שההורה שלה מתרנדר, היא סימפטום נפוץ מאוד. הפתרון לא תמיד "לעטוף הכל ב-memo" - לפעמים הפתרון הנכון הוא לפרק את העץ אחרת, כך שרק הקומפוננטה שבאמת השתנה תשב ב"אזור" שמתעדכן.

מפתחות יציבים ברשימות

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

זהירות מ-props שנוצרים מחדש בכל רינדור

זו אחת הטעויות השקטות והנפוצות ביותר. אם אתם מעבירים לקומפוננטת ילד אובייקט או פונקציה שנוצרים inline בתוך ה-JSX - למשל <Child config={{color: "blue"}} /> או <Child onClick={() => doSomething()} /> - אתם יוצרים ערך חדש לגמרי בכל רינדור, גם אם התוכן זהה. אם הקומפוננטה הילד עטופה ב-memo כדי למנוע רינדורים מיותרים, זה פשוט לא יעבוד, כי מבחינת ריאקט זה "אובייקט חדש" בכל פעם. כאן בדיוק המקום שבו useMemo ו-useCallback למניעת יצירה מחדש של חישובים וקריאות מיותרות נכנסים לתמונה - לא נעמיק כאן איך הם עובדים, זה כבר מכוסה בהרחבה בפוסט אחר, אבל שווה לזכור אותם כשורה ברשימת הבדיקה שלכם.

הכלי שאומר לכם איפה הבעיה באמת - React DevTools Profiler

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

וירטואליזציה לרשימות ארוכות

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

פיצול באנדלים - לא לטעון הכל בבת אחת

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

מודדים לפני שמאופטמים

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

לסיכום

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

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

הצטרפו לקהילה בדיסקורד