TL;DR: מסך לבן ב-React (White Screen of Death) הוא כמעט תמיד תוצאה של שגיאת ריצה (runtime error) שקורסת את כל עץ הרכיבים בלי שאף רכיב תופס אותה. הצעד הראשון תמיד זהה: פותחים את ה-Console בדפדפן וקוראים את השגיאה האמיתית. הסיבות הנפוצות: import שגוי או רכיב undefined, משתנה סביבה שחסר בפרודקשן, ו-hydration mismatch. התיקון המיידי: לזהות את השגיאה, לעטוף את האפליקציה ב-Error Boundary, ולבדוק שהבעיה לא קיימת רק ב-build ולא ב-dev. המניעה: Error Boundaries בכל שכבה קריטית וניטור שגיאות בפרודקשן.
מה רואים: דף לבן לגמרי בלי שום תוכן
הסימפטום המובהק הוא דף לבן ריק שבו שום דבר לא מתרנדר, לרוב בלי הודעת שגיאה גלויה למשתמש. האפליקציה נטענת, ה-HTML הבסיסי מגיע, אבל ה-<div id="root"> נשאר ריק. אלה הסימנים הנלווים שכדאי לשים לב אליהם:
- הדף עובד מצוין ב-
npm run devאבל מציג מסך לבן אחריnpm run buildוהעלאה לפרודקשן. - לפעמים חלק מהמסכים עובדים, ומסך מסוים אחד מפיל את כל האפליקציה.
- ב-DevTools לשונית Elements רואים ש-
<div id="root">קיים אבל ריק לחלוטין. - לעיתים יש הבהוב קצר של תוכן ואז הכל נעלם (סימן מובהק ל-hydration mismatch ב-SSR).
חשוב להבין: מסך לבן הוא לא באג בפני עצמו. זה תסמין. השגיאה האמיתית כמעט תמיד מחכה לכם בקונסול, ורק צריך לפתוח אותו.
למה זה קורה: שגיאת ריצה שמפילה את כל העץ
הסיבה השורשית ברוב המקרים היא שגיאת JavaScript לא-תפוסה בזמן הרינדור, ש-React מגיב לה בפירוק כל עץ הרכיבים. מאז React 16, כאשר שגיאה נזרקת בתוך רינדור ואין Error Boundary שתופס אותה, React מסיר את כל העץ בכוונה, כדי לא להשאיר UI במצב שבור וחצי-פונקציונלי. התוצאה למשתמש היא מסך לבן. אלה הגורמים הנפוצים, מהשכיח לנדיר:
1. Import שגוי או רכיב undefined. זו הסיבה מספר אחת. import { Button } from './Button' כשהקומפוננטה מיוצאת כ-default, או שם קובץ עם אות גדולה/קטנה שונה (בעיה שלא מורגשת ב-macOS אבל מפילה על שרת Linux). התוצאה: React מקבל undefined במקום קומפוננטה וזורק Element type is invalid.
2. משתנה סביבה שחסר בפרודקשן. קוד שמסתמך על import.meta.env.VITE_API_URL או process.env.REACT_APP_KEY, כשהמשתנה הוגדר מקומית ב-.env אבל לא הוגדר בהגדרות הפרויקט ב-Vercel. בפרודקשן הערך הוא undefined, וקריאה כמו apiUrl.replace(...) זורקת Cannot read properties of undefined וקורסת הכל.
3. גישה לערך שהוא null או undefined. user.profile.name כשה-user עדיין לא נטען, או data.items.map(...) כש-items חסר. זה קלאסי בקוד שנכתב בהנחה שהמידע תמיד קיים.
4. חוסר Error Boundary. גם שגיאה קטנה באזור שולי אחד מפילה את כל האפליקציה, פשוט כי אין שום מנגנון שתופס אותה ומגביל את הנזק לאזור מקומי.
5. Hydration mismatch. בפרויקטי SSR (Next.js וכדומה), כשה-HTML שהשרת ייצר לא תואם למה שהלקוח מרנדר בטעינה הראשונה. למשל שימוש ב-window, localStorage או Date.now() ישירות ברינדור. React מזהה חוסר התאמה וזורק שגיאת hydration.
נקודה חשובה במיוחד לצוותים שמייצרים קוד עם AI: כלי כמו Cursor או Base44 נוטים לייצר בדיוק את התבניות האלה. הם ממציאים imports לרכיבים שלא קיימים, מניחים ש-props תמיד מגיעים מלאים, ומדלגים על Error Boundaries. זו תופעה שנקראת הזיית קוד של AI, והיא גורם מוביל למסך הלבן בפרויקטים שנבנו במהירות ב-vibe coding.
איך מתקנים: מהקונסול ועד ה-build
התיקון מתחיל תמיד באיתור השגיאה האמיתית ולא בניחושים. הנה סדר הפעולות המדויק:
1. פותחים את ה-Console. ב-Chrome או Firefox לוחצים F12, עוברים ללשונית Console וטוענים מחדש. חפשו את השורה האדומה הראשונה. השגיאה הזו, על שמה ומיקומה, היא כל מה שאתם צריכים. הודעות נפוצות:
Uncaught TypeError: Cannot read properties of undefined (reading 'map')
Element type is invalid: expected a string or a class/function but got: undefined
Hydration failed because the initial UI does not match what was rendered on the server
2. מוסיפים Error Boundary. במקום שכל שגיאה תפיל הכל, עוטפים את האפליקציה ברכיב שתופס שגיאות ומציג מסך fallback:
import { Component } from 'react';
class ErrorBoundary extends Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, info) {
// כאן שולחים את השגיאה לכלי ניטור
console.error('Caught by boundary:', error, info);
}
render() {
if (this.state.hasError) {
return <div>משהו השתבש. נסו לרענן את הדף.</div>;
}
return this.props.children;
}
}
ואז עוטפים ב-main.jsx:
<ErrorBoundary>
<App />
</ErrorBoundary>
עכשיו במקום מסך לבן תקבלו הודעת fallback, וה-componentDidCatch יתעד את השגיאה. מומלץ לעטוף גם אזורים ספציפיים (כל route בנפרד) כדי שכשל מקומי לא יפיל את כל המסך.
3. משווים build מול dev. אם הבעיה מופיעה רק בפרודקשן, שחזרו אותה מקומית עם build אמיתי, לא עם שרת הפיתוח:
npm run build
npm run preview # ב-Vite
זה חושף בעיות שקיימות רק ב-build: רגישות לאותיות בשמות קבצים, tree-shaking שהסיר קוד, ומשתני סביבה חסרים.
4. בודקים משתני סביבה. ודאו שכל משתנה שקיים ב-.env המקומי מוגדר גם בהגדרות הפרויקט אצל ספק האירוח (Vercel וכדומה), ושהוא נושא את הקידומת הנכונה (VITE_ ל-Vite, NEXT_PUBLIC_ ל-Next). הוסיפו הגנה בקוד:
const apiUrl = import.meta.env.VITE_API_URL;
if (!apiUrl) {
throw new Error('VITE_API_URL is not defined');
}
שגיאה מפורשת עם שם ברור עדיפה בהרבה על מסך לבן אילם.
5. מטפלים ב-hydration. אם השגיאה היא hydration mismatch, אתרו קוד שרץ אחרת בשרת ובלקוח. גישות ל-window או localStorage צריכות לרוץ בתוך useEffect, שמתבצע רק בצד הלקוח, ולא ישירות בגוף הרינדור.
איך מונעים את זה מראש
המניעה נשענת על שתי שכבות: Error Boundaries שמגבילות נזק, וניטור שמתריע לפני שהמשתמשים מגלים. הנה מה שכדאי להטמיע כברירת מחדל:
- Error Boundaries בכל שכבה קריטית. לפחות אחד גלובלי, ורצוי אחד סביב כל route או אזור עצמאי. כך שגיאה בווידג'ט אחד לא מוחקת את כל המסך.
- ניטור שגיאות בפרודקשן. חברו כלי כמו Sentry או שירות דומה שיתעד כל שגיאת ריצה עם stack trace אמיתי. בלי זה אתם לומדים על תקלות מהמשתמשים, וזה מאוחר מדי.
- בדיקת build לפני כל deploy. הריצו
npm run build && npm run previewכחלק מהתהליך, כדי לתפוס שגיאות שלא מופיעות ב-dev. - TypeScript ו-strict null checks. הקומפיילר יתפוס גישות ל-
undefinedעוד לפני שהקוד רץ, ויחסל חלק ניכר מהגורמים למסך הלבן. - בדיקה קפדנית של קוד שנוצר ב-AI. אם אתם עובדים ב-vibe coding, אל תסמכו על imports ועל הנחות לגבי מבנה נתונים שהמודל ייצר. עברו על כל רכיב חדש וודאו שהוא באמת קיים ומיוצא נכון.
מתי זה עמוק יותר מתיקון מהיר
לפעמים המסך הלבן הוא רק הביטוי החיצוני לבעיה מבנית עמוקה יותר, ואז תיקון נקודתי לא יחזיק. אם אתם רואים את הדפוסים הבאים, מדובר בחוב טכני שדורש התייחסות רחבה:
- מסכים לבנים חוזרים ונשנים אחרי כל deploy, כל פעם ממקום אחר.
- אין שום Error Boundary בפרויקט, ואין ניטור, כך שכל תקלה היא הפתעה מוחלטת.
- הקוד נבנה במהירות בכלי AI ומעולם לא עבר בדיקת production readiness, כך שאין לכם מושג אילו עוד מוקשים מחכים.
- הבעיה מופיעה רק אצל חלק מהמשתמשים או רק בדפדפנים מסוימים, ואתם לא מצליחים לשחזר אותה.
במקרים כאלה הבעיה היא לא רכיב בודד אלא היעדר תשתית לחוסן וטיפול בשגיאות בכל האפליקציה. זה בדיוק סוג המצב שבו אפליקציית AI נשברת בפרודקשן ודורשת מבט הנדסי כולל, לא תיקון נקודתי.
אם אתם תקועים מול מסך לבן שחוזר, או שאתם חושדים שהפרויקט שנבנה ב-vibe coding לא מוכן באמת לפרודקשן, זה בדיוק מה ש-VibeScale עושה. אנחנו מתמחים בחילוץ פרויקטים לפרודקשן: איתור השורש, בניית שכבת חוסן וניטור, והפיכת הקוד ליציב. אפשר להתחיל ממסגרת הביקורת שלנו או ישירות משירות החילוץ.
מוכנים שנסתכל על הקוד שלכם? כתבו לנו בוואטסאפ ונחזור אליכם עם כיוון ראשוני.
