ניהול State בפרונטאנד: ההבדל בין Server State ל-Client State
מאת צוות מדיה דיל · 08.07.2026 · פיתוח אתרים · 5 דק׳
Server State מול Client State, React Query ו-SWR, Context ו-Signals, Zustand ו-Redux Toolkit, וטעויות סנכרון נפוצות.
מפתח שמתחיל פרויקט React שם את כל מה שמגיע מהשרת — רשימת מוצרים, פרטי משתמש, תוצאות חיפוש — באותו Redux store שמחזיק גם את המצב שהמסך מוקטן או שהמודל פתוח, ומגלה בהמשך שהוא נאבק בבאגים של קאש לא מסונכרן, refetch מיותר ולוגיקת loading שמשוכפלת בעשרות מקומות. השורש הבעייתי הוא ערבוב בין שני סוגי state שהם מהותית שונים: Server State שמגיע ממקור חיצוני ויכול להתיישן, ו-Client State שהוא באמת מקומי לממשק ואין לו "מקור אמת" אחר.
Server State: לא באמת "שלכם"
Server State מייצג נתונים שבבעלות מקור חיצוני — API, מסד נתונים — והממשק רק שואל עותק שלהם שיכול להתיישן בכל רגע אם משתמש אחר משנה את הנתון. הניהול הנכון שלו דורש caching, invalidation, refetch ברקע, טיפול ב-race conditions בין בקשות מקבילות, ומצבי loading/error עקביים. ספריות כמו React Query או SWR נבנו בדיוק בשביל זה — הן לא "ניהול state" רגיל אלא caching layer מלא שפותר את כל הבעיות האלה בלי לכתוב אותן ידנית בכל קומפוננטה שקוראת מה-API.
Client State: מה שבאמת מקומי
Client State הוא כל מה שקיים רק בממשק ואין לו מקבילה בשרת: האם תפריט פתוח, איזה טאב נבחר, ערך שדה טופס לפני שליחה, מצב Dark Mode. לסטייט הזה אין בעיית סנכרון עם מקור חיצוני, ולכן פתרונות פשוטים מתאימים לו הרבה יותר טוב — הבעיה שקורית בפועל היא שצוותים משתמשים בכלי כבד מדי (Redux מלא) לניהול דבר פשוט כמו "האם המודל פתוח", מה שמייצר boilerplate מיותר לחלוטין.
מתי Context או Signals מספיקים
React Context מתאים היטב ל-Client State שמשותף לעץ קומפוננטות שלם אבל לא משתנה בתדירות גבוהה — theme, שפה, מצב אימות משתמש. הבעיה המוכרת של Context — שכל שינוי גורם רינדור מחדש לכל הצרכנים שלו — פחות משמעותית כשמדובר בערכים שמשתנים לעיתים רחוקות. Signals (ב-Preact, Solid, או ב-React דרך useSyncExternalStore) פותרים את בעיית הרינדור המיותר בצורה עדינה יותר על ידי מעקב גרעיני אחרי בדיוק אילו רכיבים באמת קוראים כל ערך, בלי להעביר את כל העץ.
מתי צריך ספרייה ייעודית
ברגע שה-Client State הופך מורכב — מספר מקורות עדכון, לוגיקה מותנית בין שדות, היסטוריית undo/redo, או סטייט שצריך לשרוד ניווט בין דפים — ספרייה ייעודית כמו Zustand או Redux Toolkit נותנת מבנה שמונע את ה"ספגטי" של עשרות useState מפוזרים ו-prop drilling עמוק. הכלל המעשי: אם אפשר לתאר את הסטייט במשפט אחד פשוט ("המודל פתוח או סגור") זה candidate ל-useState מקומי; אם צריך תרשים כדי להסביר את זרימת העדכונים, זה candidate לספרייה.
טעויות נפוצות
הטעות הנפוצה ביותר היא לשכפל Server State לתוך Client State store — לשמור תוצאת API ב-Redux ואז לנסות לסנכרן אותה ידנית כשהיא מתיישנת, במקום לתת ל-React Query לנהל את מחזור החיים שלה. טעות שנייה נפוצה היא derived state שנשמר בנפרד במקום מחושב — למשל לשמור isFormValid כ-state עצמאי שצריך לעדכן ידנית בכל שינוי שדה, במקום לחשב אותו ישירות מה-state הקיים בכל רינדור.
השפעה על ביצועים
ערבוב לא נכון בין שני סוגי ה-state לרוב מוביל לרינדורים מיותרים ולבקשות רשת כפולות — קומפוננטה ששומרת עותק מקומי של Server State ולא מקשיבה לעדכון מהקאש המרכזי מציגה נתונים ישנים בזמן שקומפוננטה אחרת כבר עודכנה. הפרדה נכונה בין השניים, עם caching layer ייעודי ל-Server State ומבנה מינימלי ל-Client State, בדרך כלל מקטינה גם את כמות הקוד וגם את מספר הבאגים הקשורים לסנכרון.
נאבקים בבאגי סנכרון בין Redux store לנתונים שמגיעים מה-API? נשמח לעזור לכם בוואטסאפ.
תגיות: State Management · Server State · Client State · React Query · Zustand · Signals