למה אני לא תמיד רושם מפתחות בלולאה ב React

03/07/2021

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

Warning: Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.

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

ההודעה על המפתחות החסרים בתוכנית ריאקט היא לא מהמקרים האלה.

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

function ComponentWithWarning() {
    const items = [10, 20, 30];
    return (
        <ul>
            {items.map(i => <li>{i}</li>)}
        </ul>
    );
}

function ComponentWithoutWarning() {
    const items = [10, 20, 30];
    return (
        <ul>
            {items.map((i, index) => <li key={index}>{i}</li>)}
        </ul>
    );
}

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

כאן יש דוגמה לקוד ריאקט שבור שהבאג בו הוא היעדר מפתחות יציבים, ואין בו שום אזהרה בקונסול כי הוא משתמש באינדקס בתור מפתח: https://jsbin.com/wohima/edit?output

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

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

ולגבי האזהרה הרגילה של ריאקט? אני תמיד מעדיף אותה על פני כתיבת key={index} כי היא מזכירה לי שאין לי כרגע מפתח יציב ושאם ארצה להוסיף קוד שמשנה את סדר האלמנטים כדאי שאבחר קודם כזה מפתח.