React Concurrent Rendering ו-Fiber: איך רינדור הפך לבר-הפסקה

מאת צוות מדיה דיל · 02.09.2026 · טכנולוגיה · 6 דק׳

מבנה ה-Fiber, רמות עדיפות ברינדור, startTransition ו-useDeferredValue, ולמה Concurrent Rendering דורש רכיבים טהורים לחלוטין.

עד React 18, כל עדכון State היה חוסם — ברגע שה-Reconciliation התחיל, הוא רץ עד הסוף בלי הפסקה, גם אם משתמש לחץ מקש באמצע. Concurrent Rendering משנה את ההנחה הזו מהיסוד: רינדור הופך למשימה שניתן להשהות, לתעדף מחדש, ואפילו לזרוק ולהתחיל מחדש — כל זה בלי לגעת בקוד הרכיבים עצמם.

Fiber: המבנה שהופך רינדור לבר-הפסקה

הארכיטקטורה הישנה של React (Stack Reconciler) עברה על עץ הרכיבים רקורסיבית — פעולה שאי אפשר להפסיק באמצע בלי לאבד את מקום העצירה. Fiber מחליף את זה במבנה נתונים מפורש: כל רכיב הופך ל-Fiber Node ברשימה מקושרת שניתן לעבור עליה יחידה-יחידה, לעצור אחרי כל צעד, ולבדוק אם יש עבודה דחופה יותר שממתינה — ואז לחזור בדיוק לאותה נקודה. זה הבסיס הטכני שמאפשר את כל שאר היכולות של Concurrent Rendering.

רמות עדיפות: לא כל עדכון שווה

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

startTransition ו-useDeferredValue

startTransition מסמן עדכון State מפורשות כ"לא דחוף" — למשל עדכון תוצאות חיפוש כתוצאה מהקלדה, בזמן שהתו עצמו בשדה הקלט מוצג מיידית בלי להמתין לרינדור הכבד. useDeferredValue עושה משהו דומה אבל ברמת ערך בודד — מחזיק גרסה "מיושנת" זמנית של הערך בזמן שהגרסה החדשה מתעבדת ברקע. שני ה-API-ים לא משנים את התוצאה הסופית, רק את סדר העדיפויות בדרך אליה.

Time Slicing מול חסימת ה-Main Thread

בגישה הישנה, עדכון State גדול (למשל סינון רשימה של אלפי פריטים) חוסם את ה-Main Thread עד לסיום — הדפדפן "קופא" לכמה עשרות או מאות מילישניות. Time Slicing מפצל את העבודה הזו ליחידות קטנות שרצות בין Frames, כך שהדפדפן יכול עדיין להגיב לאירועי משתמש ולצייר Frames באמצע העבודה, גם אם התוצאה הסופית מוצגת מעט מאוחר יותר.

המחיר: תופעות לוואי שרצות פעמיים

מכיוון שרינדור יכול להיזרק ולהתחיל מחדש (למשל אם עדכון בעל עדיפות גבוהה יותר מגיע באמצע), פונקציית הרכיב עצמה חייבת להיות טהורה (Pure) — כל Side Effect שרץ ישירות בגוף הרכיב עלול לרוץ פעמיים. זו הסיבה ש-React 18 ב-Strict Mode מריץ רכיבים פעמיים בכוונה בסביבת פיתוח — לחשוף מוקדם קוד שמפר את ההנחה הזו, לפני שהוא הופך לבאג נדיר בפרודקשן.

Tearing: כשחלקים שונים של המסך לא מסונכרנים

בעיה עדינה ב-Concurrent Rendering היא Tearing — מצב שבו רכיבים שונים בעץ מציגים גרסאות שונות של אותו State בו-זמנית, כי הרינדור הופסק ונדחה חלקית. React פתר את זה ברמת ה-API עם useSyncExternalStore לחיבור נכון של מקורות State חיצוניים (כמו Redux) לתהליך ה-Concurrent, בלי לגרום לחוסר עקביות ויזואלי.

הקשר ל-Suspense ולטעינת נתונים

Concurrent Rendering הוא התשתית שמאפשרת ל-Suspense להציג Fallback לחלק מהעץ בזמן שחלקים אחרים כבר מוצגים — בלי זה, React לא היה יכול "להשהות" רק ענף אחד של הרינדור בזמן שממתין לנתונים. זה אותו מנגנון תשתיתי שמאפשר את ה-Streaming שמתואר במדריך על React Server Components.

ההבדל מ-SSR מסורתי

חשוב להפריד: Concurrent Rendering הוא מנגנון בצד הלקוח (בדפדפן), בעוד SSR עוסק בהפקת HTML ראשוני בצד השרת. השילוב בין השניים — HTML שמגיע מהר מהשרת, ואז Hydration שמנוהל בעדיפויות דרך Concurrent Rendering — הוא מה שמאפשר לאתר גדול להרגיש מהיר גם בטעינה ראשונית וגם באינטראקציה שאחריה.

בונים ממשק React מורכב וזקוקים לליווי בביצועים? דברו איתנו בוואטסאפ.

תגיות: React · Concurrent Rendering · Fiber · Frontend Performance

← חזרה לבלוג · צור קשר