איך לשמור מערך בסטייט של React Component

15/11/2019

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

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

1. למה שנרצה לשמור מערך בסטייט

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

הנה נקודת ההתחלה עם פקד שמציג רשימת פריטים שאפשר לבחור ממנה:

function SelectableList(props) {
  const { items } = props;
  return (
    <ul>
      {items.map(item => (
        <li key={item} style={{ direction: "rtl" }}>
          <label>
            {item}
            <input type="checkbox" />
          </label>
        </li>
      ))}
    </ul>
  );
}

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

2. הבעיה עם שמירת מערך בסטייט

נוסיף לסטייט מערך של הפריטים שנבחרו ונעדכן את המערך כל פעם שמשתמש בוחר או מבטל בחירה. ניסיון ראשון עשוי להיראות ככה אבל זה לא עובד כלל:

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

3. איך בכל זאת לשמור מערך בסטייט

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

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

בעבודה עם מערכים הפונקציות concat ו filter יצרו מערך חדש, בעוד הפונקציות splice ו push יעדכנו את הקיים. הנה הקוד המעודכן עם concat ו filter: