שינון הוא טכניקת אופטימיזציה, בדומה לאחסון במטמון. זה עובד על ידי אחסון התוצאות הקודמות של קריאת פונקציה ושימוש בתוצאות אלה בפעם הבאה שהפונקציה פועלת. זה שימושי במיוחד באפליקציות כבדות חישוב שחוזרות על קריאות פונקציות באותם פרמטרים.
אתה יכול להשתמש ב-Memoization ב-JavaScript רגיל וגם ב-React, בכמה דרכים שונות.
שינון ב-JavaScript
כדי לשחזר פונקציה ב-JavaScript, עליך לאחסן את התוצאות של אותה פונקציה במטמון. המטמון יכול להיות אובייקט עם הארגומנטים כמפתחות ותוצאות כערכים.
כאשר אתה קורא לפונקציה זו, הוא בודק תחילה אם התוצאה קיימת במטמון לפני ההפעלה. אם כן, הוא מחזיר את התוצאות המאוחסנות במטמון. אחרת, זה מבוצע.
שקול את הפונקציה הזו:
פוּנקצִיָהכיכר(מספר) {
לַחֲזוֹר מספר * מספר
}
הפונקציה קולטת ארגומנט ומחזירה את הריבוע שלו.
כדי להפעיל את הפונקציה, קרא לה עם מספר כזה:
כיכר(5) // 25
עם 5 כארגומנט, square() יפעל די מהר. עם זאת, אם הייתם מחשבים את הריבוע של 70,000, יהיה עיכוב ניכר. לא בהרבה אבל בכל זאת עיכוב. כעת, אם היית מתקשר לפונקציה מספר פעמים ועובר 70,000, היית חווה עיכוב בכל שיחה.
אתה יכול לבטל עיכוב זה באמצעות שינון.
const memoizedSquare = () => {
תן מטמון = {};
לַחֲזוֹר (מספר) => {
אם (מספר ב מטמון) {
console.log('שימוש חוזר בערך שמור');
לַחֲזוֹר מטמון[מספר];
} אַחֵר {
console.log('חישוב תוצאה');
תן תוצאה = num * num;
// מטמון ה חָדָשׁתוֹצָאָהערךלהַבָּאזְמַן
מטמון[מספר] = תוֹצָאָה;
לַחֲזוֹר תוֹצָאָה;
}
}
}
בדוגמה זו, הפונקציה בודקת אם היא חישבתה את התוצאה בעבר, על ידי בדיקה אם היא קיימת באובייקט המטמון. אם יש זה מחזיר את הערך שכבר מחושב.
כאשר הפונקציה מקבלת מספר חדש, היא מחשבת ערך חדש ומאחסנת את התוצאות במטמון לפני שהיא חוזרת.
שוב, הדוגמה הזו די פשוטה, אבל היא מסבירה איך שינון יעבוד כדי לשפר את הביצועים של תוכנית.
עליך לשנן רק פונקציות טהורות. פונקציות אלה מחזירות את אותה תוצאה כאשר אתה מעביר את אותם ארגומנטים פנימה. אם אתה משתמש בזיכרונות זיכרון על פונקציות לא טהורות, לא תשפר את הביצועים אלא תגדיל את התקורה שלך. זה בגלל שאתה בוחר מהירות על פני זיכרון בכל פעם שאתה משנן פונקציה.
שינון ב-React
אם אתה מחפש לבצע אופטימיזציה של רכיבי React, React מספקת שינון דרך ה-useMemo(), React.memo ו-useCallBack().
שימוש ב-useMemo()
useMemo() הוא א וו תגובה שמקבל פונקציה ומערך תלות.
const memoizedValue = useMemo(() => computeExpensiveValue (a, b), [a, b]);
הוא משחזר את הערך המוחזר מאותה פונקציה. הערכים במערך התלות מכתיבים מתי הפונקציה מבוצעת. רק כשהם משתנים, הפונקציה מבוצעת שוב.
לדוגמה, לרכיב האפליקציה הבא יש ערך ממוזכר בשם תוצאה.
יְבוּא { useMemo } מ "לְהָגִיב"
פוּנקצִיָהאפליקציה(ערך) {
const ריבוע = (ערך) => {
לַחֲזוֹר ערך * ערך
}
const תוצאה = useMemo(
() => ריבוע (ערך),
[ ערך ]
);
לַחֲזוֹר (
<div>{תוצאה (5)}</div>
)
}
רכיב האפליקציה קורא ל- square() בכל עיבוד. הביצועים ידרדרו אם רכיב האפליקציה יוצג פעמים רבות עקב אביזרי תגובה שינוי או עדכון מצב, במיוחד אם הפונקציה square() יקרה.
עם זאת, מכיוון ש-useMemo() מאחסן במטמון את הערכים המוחזרים, פונקציית הריבוע אינה מבוצעת בכל רינדור מחדש אלא אם כן הארגומנטים במערך התלות משתנים.
שימוש ב-React.memo()
React.memo() הוא רכיב מסדר גבוה יותר שמקבל רכיב React ופונקציה כארגומנטים. הפונקציה קובעת מתי יש לעדכן את הרכיב.
הפונקציה היא אופציונלית ואם לא מסופקת, React.memo מבצע השוואה של עותק רדוד בין האביזרים הנוכחיים של הרכיב לאביזרים הקודמים שלו. אם האביזרים שונים, זה מפעיל עדכון. אם האביזרים זהים, הוא מדלג על העיבוד מחדש ומשתמש מחדש בערכים שנשמרו בזיכרון.
הפונקציה האופציונלית מקבלת את האביזרים הקודמים ואת האביזרים הבאים כארגומנטים. לאחר מכן תוכל להשוות במפורש את האביזרים הללו כדי להחליט אם לעדכן את הרכיב או לא.
לְהָגִיב.תַזכִּיר(רְכִיב, [areEqual (prevProps, nextProps)])
בואו נסתכל תחילה על דוגמה ללא ארגומנט הפונקציה האופציונלי. להלן רכיב בשם תגובות שמקבל את השם ואת אביזרי האימייל.
פוּנקצִיָההערות ({שם, תגובה, לייקים}) {
לַחֲזוֹר (
<div>
<ע>{שֵׁם}</p>
<ע>{תגובה}</p>
<ע>{אהבת}</p>
</div>
)
}
רכיב ההערות הממוזכרות יכלול את React.memo סביבו כך:
const MemoizedComment = React.memo (תגובה)
אתה יכול להתקשר ואז לקרוא לזה כמו כל רכיב אחר של React.
<MemoizedComment name="מרי" תגובה="שינון זה נהדר" אוהב=1/>
אם אתה רוצה לבצע את השוואת האביזרים בעצמך, העבר את הפונקציה הבאה ל-React.memo כארגומנט השני.
יְבוּא לְהָגִיב מ "לְהָגִיב"
פוּנקצִיָהבדוק CommentProps(prevProps, nextProps) {
לַחֲזוֹר prevProps.name nextProps.name
&& prevProps.comment nextProps.comment
&& prevProps.likes nextProps.likes
}
const MemoizedComment = React.memo (תגובות, checkCommentProps)
אם checkProfileProps מחזיר true, הרכיב לא מעודכן. אחרת, הוא מעובד מחדש.
הפונקציה המותאמת אישית שימושית כאשר אתה רוצה להתאים אישית את העיבוד מחדש. לדוגמה, תוכל להשתמש בו כדי לעדכן את רכיב התגובות רק כאשר מספר הלייקים משתנה.
בניגוד ל-useMemo()-hook המשנן רק את הערך המוחזר של פונקציה, React.memo משחזר את כל הפונקציה.
השתמש ב-React.memo רק עבור רכיבים טהורים. כמו כן, כדי להפחית את עלויות ההשוואה, זכור רק רכיבים שהאביזרים שלהם משתנים לעתים קרובות.
שימוש ב-useCallBack()
אתה יכול להשתמש בהוק useCallBack() כדי לשחזר רכיבי פונקציה.
const memoizedCallback = useCallback(
() => {
doSomething (א, ב);
},
[א, ב],
);
הפונקציה מתעדכנת רק כאשר הערכים במערך התלות משתנים. ה-hook עובד כמו ה-callback של useMemo(), אבל הוא משחזר את רכיב הפונקציות בין עיבודים במקום לשנן ערכים.
שקול את הדוגמה הבאה של פונקציה ממוזכרת שקוראת ל-API.
יְבוּא { useCallback, useEffect } מ "לְהָגִיב";
const רכיב = () => {
const getData = useCallback(() => {
console.log('לקרוא ל-API');
}, []);
useEffect(() => {
getData();
}, [getData]);
};
הפונקציה getData() שנקראת ב-useEffect תיקרא שוב רק כאשר הערך getData משתנה.
האם כדאי לשנן?
במדריך זה למדת מהו שינון, היתרונות שלו וכיצד ליישם אותו ב-JavaScript וב-React. עם זאת, עליך לדעת ש-React כבר מהיר. ברוב המקרים, שימור רכיבים או ערכים מוסיף עלויות השוואה ואינו משפר את הביצועים. בגלל זה, זכור רק רכיבים יקרים.
React 18 גם הציג ווים חדשים כמו useId, useTransition ו-useInsertionEffect. אתה יכול להשתמש בהם כדי לשפר את הביצועים וחווית המשתמש של יישומי React.